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 package com.android.server.wifi; 17 18 import static com.android.server.wifi.HalDeviceManager.HDM_CREATE_IFACE_AP; 19 import static com.android.server.wifi.HalDeviceManager.HDM_CREATE_IFACE_AP_BRIDGE; 20 import static com.android.server.wifi.HalDeviceManager.HDM_CREATE_IFACE_STA; 21 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.content.Context; 25 import android.content.pm.PackageManager; 26 import android.hardware.wifi.WifiStatusCode; 27 import android.net.MacAddress; 28 import android.net.apf.ApfCapabilities; 29 import android.net.wifi.ScanResult; 30 import android.net.wifi.SoftApConfiguration; 31 import android.net.wifi.WifiAvailableChannel; 32 import android.net.wifi.WifiManager; 33 import android.net.wifi.WifiScanner; 34 import android.net.wifi.WifiSsid; 35 import android.os.Handler; 36 import android.os.WorkSource; 37 import android.text.TextUtils; 38 import android.util.Log; 39 import android.util.Pair; 40 import android.util.SparseArray; 41 42 import com.android.internal.annotations.VisibleForTesting; 43 import com.android.server.wifi.HalDeviceManager.InterfaceDestroyedListener; 44 import com.android.server.wifi.WifiNative.RxFateReport; 45 import com.android.server.wifi.WifiNative.TxFateReport; 46 import com.android.server.wifi.hal.WifiApIface; 47 import com.android.server.wifi.hal.WifiChip; 48 import com.android.server.wifi.hal.WifiHal; 49 import com.android.server.wifi.hal.WifiStaIface; 50 51 import com.google.errorprone.annotations.CompileTimeConstant; 52 53 import java.util.ArrayList; 54 import java.util.Arrays; 55 import java.util.HashMap; 56 import java.util.List; 57 import java.util.Set; 58 import java.util.stream.Collectors; 59 60 /** 61 * Wi-Fi Vendor HAL. 62 * Interface management is handled by the HalDeviceManager. 63 */ 64 public class WifiVendorHal { 65 66 private static final WifiLog sNoLog = new FakeWifiLog(); 67 68 /** 69 * Chatty logging should use mVerboseLog 70 */ 71 @VisibleForTesting 72 WifiLog mVerboseLog = sNoLog; 73 74 /** 75 * Errors should use mLog 76 */ 77 @VisibleForTesting 78 WifiLog mLog = new LogcatLog("WifiVendorHal"); 79 80 /** 81 * Enables or disables verbose logging 82 * 83 */ enableVerboseLogging(boolean verboseEnabled, boolean halVerboseEnabled)84 public void enableVerboseLogging(boolean verboseEnabled, boolean halVerboseEnabled) { 85 synchronized (sLock) { 86 if (verboseEnabled) { 87 mVerboseLog = mLog; 88 enter("verbose=true").flush(); 89 } else { 90 enter("verbose=false").flush(); 91 mVerboseLog = sNoLog; 92 } 93 } 94 } 95 96 /** 97 * Logs at method entry 98 * 99 * @param format string with % placeholders 100 * @return LogMessage formatter (remember to .flush()) 101 */ enter(@ompileTimeConstant final String format)102 private WifiLog.LogMessage enter(@CompileTimeConstant final String format) { 103 if (mVerboseLog == sNoLog) return sNoLog.info(format); 104 return mVerboseLog.trace(format, 1); 105 } 106 107 // Vendor HAL interface objects. 108 private WifiChip mWifiChip; 109 private HashMap<String, WifiStaIface> mWifiStaIfaces = new HashMap<>(); 110 private HashMap<String, WifiApIface> mWifiApIfaces = new HashMap<>(); 111 private static Context sContext; 112 private final HalDeviceManager mHalDeviceManager; 113 private final WifiGlobals mWifiGlobals; 114 private final SsidTranslator mSsidTranslator; 115 private final HalDeviceManagerStatusListener mHalDeviceManagerStatusCallbacks; 116 private final WifiStaIface.Callback mWifiStaIfaceEventCallback; 117 private final ChipEventCallback mWifiChipEventCallback; 118 119 // Plumbing for event handling. 120 // 121 // Being final fields, they can be accessed without synchronization under 122 // some reasonable assumptions. See 123 // https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5 124 private final Handler mHalEventHandler; 125 126 127 /** 128 * Wi-Fi chip related info. 129 */ 130 private static class WifiChipInfo { 131 public WifiChip.WifiChipCapabilities capabilities = null; 132 /** 133 * Add more chip specific parameters here. Basically it avoids frequent call to chip by 134 * caching it on {@link mCachedWifiChipInfos}. 135 */ 136 } 137 /** A cache which maps chip id to {@link WifiChipInfo} */ 138 private SparseArray<WifiChipInfo> mCachedWifiChipInfos = new SparseArray<>(); 139 WifiVendorHal(Context context, HalDeviceManager halDeviceManager, Handler handler, WifiGlobals wifiGlobals, @NonNull SsidTranslator ssidTranslator)140 public WifiVendorHal(Context context, HalDeviceManager halDeviceManager, Handler handler, 141 WifiGlobals wifiGlobals, 142 @NonNull SsidTranslator ssidTranslator) { 143 sContext = context; 144 mHalDeviceManager = halDeviceManager; 145 mHalEventHandler = handler; 146 mWifiGlobals = wifiGlobals; 147 mSsidTranslator = ssidTranslator; 148 mHalDeviceManagerStatusCallbacks = new HalDeviceManagerStatusListener(); 149 mWifiStaIfaceEventCallback = new StaIfaceEventCallback(); 150 mWifiChipEventCallback = new ChipEventCallback(); 151 } 152 153 public static final Object sLock = new Object(); 154 155 private WifiNative.VendorHalDeathEventHandler mDeathEventHandler; 156 157 /** 158 * Initialize the Hal device manager and register for status callbacks. 159 * 160 * @param handler Handler to notify if the vendor HAL dies. 161 * @return true on success, false otherwise. 162 */ initialize(WifiNative.VendorHalDeathEventHandler handler)163 public boolean initialize(WifiNative.VendorHalDeathEventHandler handler) { 164 synchronized (sLock) { 165 mHalDeviceManager.initialize(); 166 mHalDeviceManager.registerStatusListener( 167 mHalDeviceManagerStatusCallbacks, mHalEventHandler); 168 mDeathEventHandler = handler; 169 return true; 170 } 171 } 172 173 private WifiNative.VendorHalRadioModeChangeEventHandler mRadioModeChangeEventHandler; 174 175 /** 176 * Register to listen for radio mode change events from the HAL. 177 * 178 * @param handler Handler to notify when the vendor HAL detects a radio mode change. 179 */ registerRadioModeChangeHandler( WifiNative.VendorHalRadioModeChangeEventHandler handler)180 public void registerRadioModeChangeHandler( 181 WifiNative.VendorHalRadioModeChangeEventHandler handler) { 182 synchronized (sLock) { 183 mRadioModeChangeEventHandler = handler; 184 } 185 } 186 187 /** 188 * Register to listen for subsystem restart events from the HAL. 189 * 190 * @param listener SubsystemRestartListener listener object. 191 */ registerSubsystemRestartListener( HalDeviceManager.SubsystemRestartListener listener)192 public void registerSubsystemRestartListener( 193 HalDeviceManager.SubsystemRestartListener listener) { 194 mHalDeviceManager.registerSubsystemRestartListener(listener, mHalEventHandler); 195 } 196 197 /** 198 * Returns whether the vendor HAL is supported on this device or not. 199 */ isVendorHalSupported()200 public boolean isVendorHalSupported() { 201 synchronized (sLock) { 202 return mHalDeviceManager.isSupported(); 203 } 204 } 205 206 /** 207 * Returns whether the vendor HAL is ready or not. 208 */ isVendorHalReady()209 public boolean isVendorHalReady() { 210 synchronized (sLock) { 211 return mHalDeviceManager.isReady(); 212 } 213 } 214 215 /** 216 * Bring up the Vendor HAL and configure for STA (Station) mode 217 * 218 * @return true for success 219 */ startVendorHalSta(@onNull ConcreteClientModeManager concreteClientModeManager)220 public boolean startVendorHalSta(@NonNull ConcreteClientModeManager concreteClientModeManager) { 221 synchronized (sLock) { 222 if (!startVendorHal()) { 223 return false; 224 } 225 if (TextUtils.isEmpty(createStaIface(null, null, 226 concreteClientModeManager))) { 227 stopVendorHal(); 228 return false; 229 } 230 return true; 231 } 232 } 233 234 /** 235 * Bring up the Vendor HAL. 236 * @return true on success, false otherwise. 237 */ startVendorHal()238 public boolean startVendorHal() { 239 synchronized (sLock) { 240 if (!mHalDeviceManager.start()) { 241 mLog.err("Failed to start vendor HAL").flush(); 242 return false; 243 } 244 mLog.info("Vendor Hal started successfully").flush(); 245 return true; 246 } 247 } 248 249 250 /** Helper method to lookup the corresponding STA iface object using iface name. */ getStaIface(@onNull String ifaceName)251 private WifiStaIface getStaIface(@NonNull String ifaceName) { 252 synchronized (sLock) { 253 return mWifiStaIfaces.get(ifaceName); 254 } 255 } 256 257 private class StaInterfaceDestroyedListenerInternal implements InterfaceDestroyedListener { 258 private final InterfaceDestroyedListener mExternalListener; 259 StaInterfaceDestroyedListenerInternal(InterfaceDestroyedListener externalListener)260 StaInterfaceDestroyedListenerInternal(InterfaceDestroyedListener externalListener) { 261 mExternalListener = externalListener; 262 } 263 264 @Override onDestroyed(@onNull String ifaceName)265 public void onDestroyed(@NonNull String ifaceName) { 266 synchronized (sLock) { 267 mWifiStaIfaces.remove(ifaceName); 268 } 269 if (mExternalListener != null) { 270 mExternalListener.onDestroyed(ifaceName); 271 } 272 } 273 } 274 275 /** 276 * Create a STA iface using {@link HalDeviceManager}. 277 * 278 * @param destroyedListener Listener to be invoked when the interface is destroyed. 279 * @param requestorWs Requestor worksource. 280 * @param concreteClientModeManager ConcreteClientModeManager requesting the interface. 281 * @return iface name on success, null otherwise. 282 */ createStaIface(@ullable InterfaceDestroyedListener destroyedListener, @NonNull WorkSource requestorWs, @NonNull ConcreteClientModeManager concreteClientModeManager)283 public String createStaIface(@Nullable InterfaceDestroyedListener destroyedListener, 284 @NonNull WorkSource requestorWs, 285 @NonNull ConcreteClientModeManager concreteClientModeManager) { 286 synchronized (sLock) { 287 WifiStaIface iface = mHalDeviceManager.createStaIface( 288 new StaInterfaceDestroyedListenerInternal(destroyedListener), mHalEventHandler, 289 requestorWs, concreteClientModeManager); 290 if (iface == null) { 291 mLog.err("Failed to create STA iface").flush(); 292 return null; 293 } 294 String ifaceName = iface.getName(); 295 if (TextUtils.isEmpty(ifaceName)) { 296 mLog.err("Failed to get iface name").flush(); 297 return null; 298 } 299 if (!registerStaIfaceCallback(iface)) { 300 mLog.err("Failed to register STA iface callback").flush(); 301 return null; 302 } 303 if (!retrieveWifiChip(iface)) { 304 mLog.err("Failed to get wifi chip").flush(); 305 return null; 306 } 307 mWifiStaIfaces.put(ifaceName, iface); 308 return ifaceName; 309 } 310 } 311 312 /** 313 * Replace the requestor worksource info for a STA iface using {@link HalDeviceManager}. 314 * 315 * @param ifaceName Name of the interface being removed. 316 * @param requestorWs Requestor worksource. 317 * @return true on success, false otherwise. 318 */ replaceStaIfaceRequestorWs(@onNull String ifaceName, @NonNull WorkSource requestorWs)319 public boolean replaceStaIfaceRequestorWs(@NonNull String ifaceName, 320 @NonNull WorkSource requestorWs) { 321 synchronized (sLock) { 322 WifiStaIface iface = getStaIface(ifaceName); 323 if (iface == null) return false; 324 325 if (!mHalDeviceManager.replaceRequestorWs(iface, requestorWs)) { 326 mLog.err("Failed to replace requestor worksource for STA iface").flush(); 327 return false; 328 } 329 return true; 330 } 331 } 332 333 /** 334 * Remove a STA iface using {@link HalDeviceManager}. 335 * 336 * @param ifaceName Name of the interface being removed. 337 * @return true on success, false otherwise. 338 */ removeStaIface(@onNull String ifaceName)339 public boolean removeStaIface(@NonNull String ifaceName) { 340 synchronized (sLock) { 341 WifiStaIface iface = getStaIface(ifaceName); 342 if (iface == null) return false; 343 if (!mHalDeviceManager.removeIface(iface)) { 344 mLog.err("Failed to remove STA iface").flush(); 345 return false; 346 } 347 mWifiStaIfaces.remove(ifaceName); 348 return true; 349 } 350 } 351 352 /** Helper method to lookup the corresponding AP iface object using iface name. */ getApIface(@onNull String ifaceName)353 private WifiApIface getApIface(@NonNull String ifaceName) { 354 synchronized (sLock) { 355 return mWifiApIfaces.get(ifaceName); 356 } 357 } 358 359 private class ApInterfaceDestroyedListenerInternal implements InterfaceDestroyedListener { 360 private final InterfaceDestroyedListener mExternalListener; 361 ApInterfaceDestroyedListenerInternal(InterfaceDestroyedListener externalListener)362 ApInterfaceDestroyedListenerInternal(InterfaceDestroyedListener externalListener) { 363 mExternalListener = externalListener; 364 } 365 366 @Override onDestroyed(@onNull String ifaceName)367 public void onDestroyed(@NonNull String ifaceName) { 368 synchronized (sLock) { 369 mWifiApIfaces.remove(ifaceName); 370 } 371 if (mExternalListener != null) { 372 mExternalListener.onDestroyed(ifaceName); 373 } 374 } 375 } 376 getNecessaryCapabilitiesForSoftApMode(@oftApConfiguration.BandType int band)377 private long getNecessaryCapabilitiesForSoftApMode(@SoftApConfiguration.BandType int band) { 378 long caps = HalDeviceManager.CHIP_CAPABILITY_ANY; 379 if ((band & SoftApConfiguration.BAND_60GHZ) != 0) { 380 caps |= WifiManager.WIFI_FEATURE_INFRA_60G; 381 } 382 return caps; 383 } 384 385 /** 386 * Create an AP iface using {@link HalDeviceManager}. 387 * 388 * @param destroyedListener Listener to be invoked when the interface is destroyed. 389 * @param requestorWs Requestor worksource. 390 * @param band The requesting band for this AP interface. 391 * @param isBridged Whether or not AP interface is a bridge interface. 392 * @param softApManager SoftApManager of the request. 393 * @return iface name on success, null otherwise. 394 */ createApIface(@ullable InterfaceDestroyedListener destroyedListener, @NonNull WorkSource requestorWs, @SoftApConfiguration.BandType int band, boolean isBridged, @NonNull SoftApManager softApManager)395 public String createApIface(@Nullable InterfaceDestroyedListener destroyedListener, 396 @NonNull WorkSource requestorWs, 397 @SoftApConfiguration.BandType int band, 398 boolean isBridged, 399 @NonNull SoftApManager softApManager) { 400 synchronized (sLock) { 401 WifiApIface iface = mHalDeviceManager.createApIface( 402 getNecessaryCapabilitiesForSoftApMode(band), 403 new ApInterfaceDestroyedListenerInternal(destroyedListener), mHalEventHandler, 404 requestorWs, isBridged, softApManager); 405 if (iface == null) { 406 mLog.err("Failed to create AP iface").flush(); 407 return null; 408 } 409 String ifaceName = iface.getName(); 410 if (TextUtils.isEmpty(ifaceName)) { 411 mLog.err("Failed to get iface name").flush(); 412 return null; 413 } 414 if (!retrieveWifiChip(iface)) { 415 mLog.err("Failed to get wifi chip").flush(); 416 return null; 417 } 418 mWifiApIfaces.put(ifaceName, iface); 419 return ifaceName; 420 } 421 } 422 423 /** 424 * Replace the requestor worksource info for an AP iface using {@link HalDeviceManager}. 425 * 426 * @param ifaceName Name of the interface being removed. 427 * @param requestorWs Requestor worksource. 428 * @return true on success, false otherwise. 429 */ replaceApIfaceRequestorWs(@onNull String ifaceName, @NonNull WorkSource requestorWs)430 public boolean replaceApIfaceRequestorWs(@NonNull String ifaceName, 431 @NonNull WorkSource requestorWs) { 432 synchronized (sLock) { 433 WifiApIface iface = getApIface(ifaceName); 434 if (iface == null) return false; 435 436 if (!mHalDeviceManager.replaceRequestorWs(iface, requestorWs)) { 437 mLog.err("Failed to replace requestor worksource for AP iface").flush(); 438 return false; 439 } 440 return true; 441 } 442 } 443 444 /** 445 * Remove an AP iface using {@link HalDeviceManager}. 446 * 447 * @param ifaceName Name of the interface being removed. 448 * @return true on success, false otherwise. 449 */ removeApIface(@onNull String ifaceName)450 public boolean removeApIface(@NonNull String ifaceName) { 451 synchronized (sLock) { 452 WifiApIface iface = getApIface(ifaceName); 453 if (iface == null) return false; 454 455 if (!mHalDeviceManager.removeIface(iface)) { 456 mLog.err("Failed to remove AP iface").flush(); 457 return false; 458 } 459 mWifiApIfaces.remove(ifaceName); 460 return true; 461 } 462 } 463 464 /** 465 * Helper function to remove specific instance in bridged AP iface. 466 * 467 * @param ifaceName Name of the iface. 468 * @param apIfaceInstance The identity of the ap instance. 469 * @return true if the operation succeeded, false if there is an error in Hal. 470 */ removeIfaceInstanceFromBridgedApIface(@onNull String ifaceName, @NonNull String apIfaceInstance)471 public boolean removeIfaceInstanceFromBridgedApIface(@NonNull String ifaceName, 472 @NonNull String apIfaceInstance) { 473 if (mWifiChip == null) return false; 474 return mWifiChip.removeIfaceInstanceFromBridgedApIface(ifaceName, apIfaceInstance); 475 } 476 477 /** 478 * Set the current coex unsafe channels to avoid and their restrictions. 479 * @param unsafeChannels List of {@link android.net.wifi.CoexUnsafeChannel} to avoid. 480 * @param restrictions int containing a bitwise-OR combination of 481 * {@link WifiManager.CoexRestriction}. 482 * @return true if the operation succeeded, false if there is an error in Hal. 483 */ setCoexUnsafeChannels( @onNull List<android.net.wifi.CoexUnsafeChannel> unsafeChannels, int restrictions)484 public boolean setCoexUnsafeChannels( 485 @NonNull List<android.net.wifi.CoexUnsafeChannel> unsafeChannels, int restrictions) { 486 if (mWifiChip == null) return false; 487 return mWifiChip.setCoexUnsafeChannels(unsafeChannels, restrictions); 488 } 489 retrieveWifiChip(WifiHal.WifiInterface iface)490 private boolean retrieveWifiChip(WifiHal.WifiInterface iface) { 491 synchronized (sLock) { 492 boolean registrationNeeded = mWifiChip == null; 493 mWifiChip = mHalDeviceManager.getChip(iface); 494 if (mWifiChip == null) { 495 mLog.err("Failed to get the chip created for the Iface").flush(); 496 return false; 497 } 498 if (!registrationNeeded) { 499 return true; 500 } 501 if (!registerChipCallback()) { 502 mLog.err("Failed to register chip callback").flush(); 503 mWifiChip = null; 504 return false; 505 } 506 cacheWifiChipInfo(mWifiChip); 507 return true; 508 } 509 } 510 511 /** 512 * Registers the sta iface callback. 513 */ registerStaIfaceCallback(WifiStaIface iface)514 private boolean registerStaIfaceCallback(WifiStaIface iface) { 515 synchronized (sLock) { 516 if (iface == null) return false; 517 if (mWifiStaIfaceEventCallback == null) return false; 518 return iface.registerFrameworkCallback(mWifiStaIfaceEventCallback); 519 } 520 } 521 522 /** 523 * Registers the sta iface callback. 524 */ registerChipCallback()525 private boolean registerChipCallback() { 526 synchronized (sLock) { 527 if (mWifiChip == null) return false; 528 return mWifiChip.registerCallback(mWifiChipEventCallback); 529 } 530 } 531 532 /** 533 * Stops the HAL 534 */ stopVendorHal()535 public void stopVendorHal() { 536 synchronized (sLock) { 537 mHalDeviceManager.stop(); 538 clearState(); 539 mLog.info("Vendor Hal stopped").flush(); 540 } 541 } 542 543 /** 544 * Clears the state associated with a started Iface 545 * 546 * Caller should hold the lock. 547 */ clearState()548 private void clearState() { 549 mWifiChip = null; 550 mWifiStaIfaces.clear(); 551 mWifiApIfaces.clear(); 552 mDriverDescription = null; 553 mFirmwareDescription = null; 554 } 555 556 /** 557 * Tests whether the HAL is started and at least one iface is up. 558 */ isHalStarted()559 public boolean isHalStarted() { 560 // For external use only. Methods in this class should test for null directly. 561 synchronized (sLock) { 562 return (!mWifiStaIfaces.isEmpty() || !mWifiApIfaces.isEmpty()); 563 } 564 } 565 566 /** 567 * Gets the scan capabilities 568 * 569 * @param ifaceName Name of the interface. 570 * @param capabilities object to be filled in 571 * @return true for success, false for failure 572 */ getBgScanCapabilities( @onNull String ifaceName, WifiNative.ScanCapabilities capabilities)573 public boolean getBgScanCapabilities( 574 @NonNull String ifaceName, WifiNative.ScanCapabilities capabilities) { 575 synchronized (sLock) { 576 WifiStaIface iface = getStaIface(ifaceName); 577 if (iface == null) return false; 578 579 WifiNative.ScanCapabilities result = iface.getBackgroundScanCapabilities(); 580 if (result != null) { 581 capabilities.max_scan_cache_size = result.max_scan_cache_size; 582 capabilities.max_ap_cache_per_scan = result.max_ap_cache_per_scan; 583 capabilities.max_scan_buckets = result.max_scan_buckets; 584 capabilities.max_rssi_sample_size = result.max_rssi_sample_size; 585 capabilities.max_scan_reporting_threshold = result.max_scan_reporting_threshold; 586 } 587 return result != null; 588 } 589 } 590 591 /** 592 * Holds the current background scan state, to implement pause and restart 593 */ 594 @VisibleForTesting 595 class CurrentBackgroundScan { 596 public int cmdId; 597 public WifiStaIface.StaBackgroundScanParameters param; 598 public WifiNative.ScanEventHandler eventHandler = null; 599 public boolean paused = false; 600 public WifiScanner.ScanData[] latestScanResults = null; 601 CurrentBackgroundScan(int id, WifiNative.ScanSettings settings)602 CurrentBackgroundScan(int id, WifiNative.ScanSettings settings) { 603 cmdId = id; 604 List<WifiNative.BucketSettings> buckets = new ArrayList<>(); 605 if (settings.buckets != null) { 606 buckets = Arrays.asList(settings.buckets); 607 } 608 param = new WifiStaIface.StaBackgroundScanParameters(settings.base_period_ms, 609 settings.max_ap_per_scan, settings.report_threshold_percent, 610 settings.report_threshold_num_scans, buckets); 611 } 612 } 613 614 private int mLastScanCmdId; // For assigning cmdIds to scans 615 616 @VisibleForTesting 617 CurrentBackgroundScan mScan = null; 618 619 /** 620 * Starts a background scan 621 * 622 * Any ongoing scan will be stopped first 623 * 624 * @param ifaceName Name of the interface. 625 * @param settings to control the scan 626 * @param eventHandler to call with the results 627 * @return true for success 628 */ startBgScan(@onNull String ifaceName, WifiNative.ScanSettings settings, WifiNative.ScanEventHandler eventHandler)629 public boolean startBgScan(@NonNull String ifaceName, 630 WifiNative.ScanSettings settings, 631 WifiNative.ScanEventHandler eventHandler) { 632 if (eventHandler == null) return false; 633 synchronized (sLock) { 634 WifiStaIface iface = getStaIface(ifaceName); 635 if (iface == null) return false; 636 if (mScan != null && !mScan.paused) { 637 iface.stopBackgroundScan(mScan.cmdId); 638 mScan = null; 639 } 640 641 mLastScanCmdId = (mLastScanCmdId % 9) + 1; // cycle through non-zero single digits 642 CurrentBackgroundScan scan = new CurrentBackgroundScan(mLastScanCmdId, settings); 643 boolean success = iface.startBackgroundScan(scan.cmdId, scan.param); 644 if (!success) return false; 645 646 scan.eventHandler = eventHandler; 647 mScan = scan; 648 return true; 649 } 650 } 651 652 653 /** 654 * Stops any ongoing background scan 655 * 656 * @param ifaceName Name of the interface. 657 */ stopBgScan(@onNull String ifaceName)658 public void stopBgScan(@NonNull String ifaceName) { 659 synchronized (sLock) { 660 WifiStaIface iface = getStaIface(ifaceName); 661 if (iface == null) return; 662 if (mScan != null) { 663 iface.stopBackgroundScan(mScan.cmdId); 664 mScan = null; 665 } 666 } 667 } 668 669 /** 670 * Pauses an ongoing background scan 671 * 672 * @param ifaceName Name of the interface. 673 */ pauseBgScan(@onNull String ifaceName)674 public void pauseBgScan(@NonNull String ifaceName) { 675 synchronized (sLock) { 676 WifiStaIface iface = getStaIface(ifaceName); 677 if (iface == null) return; 678 if (mScan != null && !mScan.paused) { 679 if (!iface.stopBackgroundScan(mScan.cmdId)) return; 680 mScan.paused = true; 681 } 682 } 683 } 684 685 /** 686 * Restarts a paused background scan 687 * 688 * @param ifaceName Name of the interface. 689 */ restartBgScan(@onNull String ifaceName)690 public void restartBgScan(@NonNull String ifaceName) { 691 synchronized (sLock) { 692 WifiStaIface iface = getStaIface(ifaceName); 693 if (iface == null) return; 694 if (mScan != null && mScan.paused) { 695 if (!iface.startBackgroundScan(mScan.cmdId, mScan.param)) return; 696 mScan.paused = false; 697 } 698 } 699 } 700 701 /** 702 * Gets the latest scan results received from the HAL interface callback. 703 * 704 * @param ifaceName Name of the interface. 705 */ getBgScanResults(@onNull String ifaceName)706 public WifiScanner.ScanData[] getBgScanResults(@NonNull String ifaceName) { 707 synchronized (sLock) { 708 WifiStaIface iface = getStaIface(ifaceName); 709 if (iface == null) return null; 710 if (mScan == null) return null; 711 return mScan.latestScanResults; 712 } 713 } 714 715 /** 716 * Get the link layer statistics 717 * 718 * Note - we always enable link layer stats on a STA interface. 719 * 720 * @param ifaceName Name of the interface. 721 * @return the statistics, or null if unable to do so 722 */ getWifiLinkLayerStats(@onNull String ifaceName)723 public WifiLinkLayerStats getWifiLinkLayerStats(@NonNull String ifaceName) { 724 synchronized (sLock) { 725 WifiStaIface iface = getStaIface(ifaceName); 726 if (iface == null) return null; 727 return iface.getLinkLayerStats(); 728 } 729 } 730 731 @VisibleForTesting 732 boolean mLinkLayerStatsDebug = false; // Passed to Hal 733 734 /** 735 * Enables the linkLayerStats in the Hal. 736 * 737 * This is called unconditionally whenever we create a STA interface. 738 * 739 * @param ifaceName Name of the interface. 740 */ enableLinkLayerStats(@onNull String ifaceName)741 public void enableLinkLayerStats(@NonNull String ifaceName) { 742 synchronized (sLock) { 743 WifiStaIface iface = getStaIface(ifaceName); 744 if (iface == null) { 745 mLog.err("STA iface object is NULL - Failed to enable link layer stats") 746 .flush(); 747 return; 748 } 749 if (!iface.enableLinkLayerStatsCollection(mLinkLayerStatsDebug)) { 750 mLog.err("unable to enable link layer stats collection").flush(); 751 } 752 } 753 } 754 755 /** 756 * Translation table used by getSupportedFeatureSetFromPackageManager 757 * for translating System caps 758 */ 759 private static final Pair[] sSystemFeatureCapabilityTranslation = new Pair[] { 760 Pair.create(WifiManager.WIFI_FEATURE_INFRA, PackageManager.FEATURE_WIFI), 761 Pair.create(WifiManager.WIFI_FEATURE_P2P, PackageManager.FEATURE_WIFI_DIRECT), 762 Pair.create(WifiManager.WIFI_FEATURE_AWARE, PackageManager.FEATURE_WIFI_AWARE), 763 }; 764 765 /** 766 * If VendorHal is not supported, reading PackageManager 767 * system features to return basic capabilities. 768 * 769 * @return bitmask defined by WifiManager.WIFI_FEATURE_* 770 */ getSupportedFeatureSetFromPackageManager()771 private long getSupportedFeatureSetFromPackageManager() { 772 long featureSet = 0; 773 final PackageManager pm = sContext.getPackageManager(); 774 for (Pair pair: sSystemFeatureCapabilityTranslation) { 775 if (pm.hasSystemFeature((String) pair.second)) { 776 featureSet |= (long) pair.first; 777 } 778 } 779 enter("System feature set: %").c(featureSet).flush(); 780 return featureSet; 781 } 782 783 /** 784 * Get maximum number of links supported by the chip for MLO association. 785 * 786 * @param ifaceName Name of the interface. 787 * @return maximum number of association links or -1 if error or not available. 788 */ getMaxMloAssociationLinkCount(String ifaceName)789 public int getMaxMloAssociationLinkCount(String ifaceName) { 790 WifiChipInfo wifiChipInfo = getCachedWifiChipInfo( 791 ifaceName); 792 if (wifiChipInfo == null || wifiChipInfo.capabilities == null) return -1; 793 return wifiChipInfo.capabilities.maxMloAssociationLinkCount; 794 } 795 796 /** 797 * Get the maximum number of STR links used in Multi-Link Operation. 798 * 799 * @param ifaceName Name of the interface. 800 * @return maximum number of MLO STR links or -1 if error or not available. 801 */ getMaxMloStrLinkCount(String ifaceName)802 public int getMaxMloStrLinkCount(String ifaceName) { 803 WifiChipInfo wifiChipInfo = getCachedWifiChipInfo( 804 ifaceName); 805 if (wifiChipInfo == null || wifiChipInfo.capabilities == null) return -1; 806 return wifiChipInfo.capabilities.maxMloStrLinkCount; 807 } 808 809 /** 810 * Get the maximum number of concurrent TDLS sessions supported by the device. 811 * 812 * @param ifaceName Name of the interface. 813 * @return maximum number of concurrent TDLS sessions or -1 if error or not available. 814 */ getMaxSupportedConcurrentTdlsSessions(String ifaceName)815 public int getMaxSupportedConcurrentTdlsSessions(String ifaceName) { 816 WifiChipInfo wifiChipInfo = getCachedWifiChipInfo( 817 ifaceName); 818 if (wifiChipInfo == null || wifiChipInfo.capabilities == null) return -1; 819 return wifiChipInfo.capabilities.maxConcurrentTdlsSessionCount; 820 } 821 822 /** 823 * Get Chip specific cached info. 824 * 825 * @param ifaceName Name of the interface 826 * @return the cached information. 827 */ getCachedWifiChipInfo(String ifaceName)828 private WifiChipInfo getCachedWifiChipInfo(String ifaceName) { 829 WifiStaIface iface = getStaIface(ifaceName); 830 if (iface == null) return null; 831 832 WifiChip chip = mHalDeviceManager.getChip(iface); 833 if (chip == null) return null; 834 835 return mCachedWifiChipInfos.get(chip.getId()); 836 } 837 838 /** 839 * Cache chip specific info. 840 * 841 * @param chip Wi-Fi chip 842 */ cacheWifiChipInfo(@onNull WifiChip chip)843 private void cacheWifiChipInfo(@NonNull WifiChip chip) { 844 if (mCachedWifiChipInfos.contains(chip.getId())) return; 845 WifiChipInfo wifiChipInfo = new WifiChipInfo(); 846 wifiChipInfo.capabilities = chip.getWifiChipCapabilities(); 847 mCachedWifiChipInfos.put(chip.getId(), wifiChipInfo); 848 } 849 850 /** 851 * Get the supported features 852 * 853 * The result may differ depending on the mode (STA or AP) 854 * 855 * @param ifaceName Name of the interface. 856 * @return bitmask defined by WifiManager.WIFI_FEATURE_* 857 */ getSupportedFeatureSet(@onNull String ifaceName)858 public long getSupportedFeatureSet(@NonNull String ifaceName) { 859 long featureSet = 0L; 860 if (!mHalDeviceManager.isStarted() || !mHalDeviceManager.isSupported()) { 861 return getSupportedFeatureSetFromPackageManager(); 862 } 863 864 synchronized (sLock) { 865 if (mWifiChip != null) { 866 WifiChip.Response<Long> capsResp = mWifiChip.getCapabilitiesAfterIfacesExist(); 867 if (capsResp.getStatusCode() == WifiHal.WIFI_STATUS_SUCCESS) { 868 featureSet = capsResp.getValue(); 869 } else if (capsResp.getStatusCode() == WifiHal.WIFI_STATUS_ERROR_REMOTE_EXCEPTION) { 870 return 0; 871 } 872 } 873 874 WifiStaIface iface = getStaIface(ifaceName); 875 if (iface != null) { 876 featureSet |= iface.getCapabilities(); 877 if (mHalDeviceManager.is24g5gDbsSupported(iface) 878 || mHalDeviceManager.is5g6gDbsSupported(iface)) { 879 featureSet |= WifiManager.WIFI_FEATURE_DUAL_BAND_SIMULTANEOUS; 880 } 881 } 882 } 883 884 if (mWifiGlobals.isWpa3SaeH2eSupported()) { 885 featureSet |= WifiManager.WIFI_FEATURE_SAE_H2E; 886 } 887 888 Set<Integer> supportedIfaceTypes = mHalDeviceManager.getSupportedIfaceTypes(); 889 if (supportedIfaceTypes.contains(WifiChip.IFACE_TYPE_STA)) { 890 featureSet |= WifiManager.WIFI_FEATURE_INFRA; 891 } 892 if (supportedIfaceTypes.contains(WifiChip.IFACE_TYPE_AP)) { 893 featureSet |= WifiManager.WIFI_FEATURE_MOBILE_HOTSPOT; 894 } 895 if (supportedIfaceTypes.contains(WifiChip.IFACE_TYPE_P2P)) { 896 featureSet |= WifiManager.WIFI_FEATURE_P2P; 897 } 898 if (supportedIfaceTypes.contains(WifiChip.IFACE_TYPE_NAN)) { 899 featureSet |= WifiManager.WIFI_FEATURE_AWARE; 900 } 901 902 return featureSet; 903 } 904 905 /** 906 * Set Mac address on the given interface 907 * 908 * @param ifaceName Name of the interface 909 * @param mac MAC address to change into 910 * @return true for success 911 */ setStaMacAddress(@onNull String ifaceName, @NonNull MacAddress mac)912 public boolean setStaMacAddress(@NonNull String ifaceName, @NonNull MacAddress mac) { 913 synchronized (sLock) { 914 WifiStaIface iface = getStaIface(ifaceName); 915 if (iface == null) return false; 916 return iface.setMacAddress(mac); 917 } 918 } 919 920 /** 921 * Reset MAC address to factory MAC address on the given interface 922 * 923 * @param ifaceName Name of the interface 924 * @return true for success 925 */ resetApMacToFactoryMacAddress(@onNull String ifaceName)926 public boolean resetApMacToFactoryMacAddress(@NonNull String ifaceName) { 927 synchronized (sLock) { 928 WifiApIface iface = getApIface(ifaceName); 929 if (iface == null) return false; 930 return iface.resetToFactoryMacAddress(); 931 } 932 } 933 934 /** 935 * Set Mac address on the given interface 936 * 937 * @param ifaceName Name of the interface 938 * @param mac MAC address to change into 939 * @return true for success 940 */ setApMacAddress(@onNull String ifaceName, @NonNull MacAddress mac)941 public boolean setApMacAddress(@NonNull String ifaceName, @NonNull MacAddress mac) { 942 synchronized (sLock) { 943 WifiApIface iface = getApIface(ifaceName); 944 if (iface == null) return false; 945 return iface.setMacAddress(mac); 946 } 947 } 948 949 /** 950 * Returns true if Hal version supports setMacAddress, otherwise false. 951 * 952 * @param ifaceName Name of the interface 953 */ isApSetMacAddressSupported(@onNull String ifaceName)954 public boolean isApSetMacAddressSupported(@NonNull String ifaceName) { 955 synchronized (sLock) { 956 WifiApIface iface = getApIface(ifaceName); 957 if (iface == null) return false; 958 return iface.isSetMacAddressSupported(); 959 } 960 } 961 962 /** 963 * Get factory MAC address of the given interface 964 * 965 * @param ifaceName Name of the interface 966 * @return factory MAC address of the interface or null. 967 */ getStaFactoryMacAddress(@onNull String ifaceName)968 public MacAddress getStaFactoryMacAddress(@NonNull String ifaceName) { 969 synchronized (sLock) { 970 WifiStaIface iface = getStaIface(ifaceName); 971 if (iface == null) return null; 972 return iface.getFactoryMacAddress(); 973 } 974 } 975 976 /** 977 * Get factory MAC address of the given interface 978 * 979 * @param ifaceName Name of the interface 980 * @return factory MAC address of the interface or null. 981 */ getApFactoryMacAddress(@onNull String ifaceName)982 public MacAddress getApFactoryMacAddress(@NonNull String ifaceName) { 983 synchronized (sLock) { 984 WifiApIface iface = getApIface(ifaceName); 985 if (iface == null) return null; 986 return iface.getFactoryMacAddress(); 987 } 988 } 989 990 /** 991 * Get the APF (Android Packet Filter) capabilities of the device 992 * 993 * @param ifaceName Name of the interface. 994 * @return APF capabilities object. 995 */ getApfCapabilities(@onNull String ifaceName)996 public ApfCapabilities getApfCapabilities(@NonNull String ifaceName) { 997 synchronized (sLock) { 998 WifiStaIface iface = getStaIface(ifaceName); 999 if (iface == null) return sNoApfCapabilities; 1000 return iface.getApfPacketFilterCapabilities(); 1001 } 1002 } 1003 1004 private static final ApfCapabilities sNoApfCapabilities = new ApfCapabilities(0, 0, 0); 1005 1006 /** 1007 * Installs an APF program on this iface, replacing any existing program. 1008 * 1009 * @param ifaceName Name of the interface. 1010 * @param filter is the android packet filter program 1011 * @return true for success 1012 */ installPacketFilter(@onNull String ifaceName, byte[] filter)1013 public boolean installPacketFilter(@NonNull String ifaceName, byte[] filter) { 1014 if (filter == null) return false; 1015 enter("filter length %").c(filter.length).flush(); 1016 synchronized (sLock) { 1017 WifiStaIface iface = getStaIface(ifaceName); 1018 if (iface == null) return false; 1019 return iface.installApfPacketFilter(filter); 1020 } 1021 } 1022 1023 /** 1024 * Reads the APF program and data buffer on this iface. 1025 * 1026 * @param ifaceName Name of the interface 1027 * @return the buffer returned by the driver, or null in case of an error 1028 */ readPacketFilter(@onNull String ifaceName)1029 public byte[] readPacketFilter(@NonNull String ifaceName) { 1030 enter("").flush(); 1031 // TODO: Must also take the wakelock here to prevent going to sleep with APF disabled. 1032 synchronized (sLock) { 1033 WifiStaIface iface = getStaIface(ifaceName); 1034 if (iface == null) return null; 1035 return iface.readApfPacketFilterData(); 1036 } 1037 } 1038 1039 /** 1040 * Set country code for this Wifi chip 1041 * 1042 * @param countryCode - two-letter country code (as ISO 3166) 1043 * @return true for success 1044 */ setChipCountryCode(String countryCode)1045 public boolean setChipCountryCode(String countryCode) { 1046 synchronized (sLock) { 1047 if (mWifiChip == null) return false; 1048 return mWifiChip.setCountryCode(countryCode); 1049 } 1050 } 1051 1052 /** 1053 * Get the names of the bridged AP instances. 1054 * 1055 * @param ifaceName Name of the bridged interface. 1056 * @return A list which contains the names of the bridged AP instances. 1057 */ 1058 @Nullable getBridgedApInstances(@onNull String ifaceName)1059 public List<String> getBridgedApInstances(@NonNull String ifaceName) { 1060 synchronized (sLock) { 1061 WifiApIface iface = getApIface(ifaceName); 1062 if (iface == null) return null; 1063 return iface.getBridgedInstances(); 1064 } 1065 } 1066 1067 /** 1068 * Set country code for this AP iface. 1069 * 1070 * @param ifaceName Name of the interface. 1071 * @param countryCode - two-letter country code (as ISO 3166) 1072 * @return true for success 1073 */ setApCountryCode(@onNull String ifaceName, String countryCode)1074 public boolean setApCountryCode(@NonNull String ifaceName, String countryCode) { 1075 synchronized (sLock) { 1076 WifiApIface iface = getApIface(ifaceName); 1077 if (iface == null) return false; 1078 return iface.setCountryCode(countryCode); 1079 } 1080 } 1081 1082 private WifiNative.WifiLoggerEventHandler mLogEventHandler = null; 1083 1084 /** 1085 * Registers the logger callback and enables alerts. 1086 * Ring buffer data collection is only triggered when |startLoggingRingBuffer| is invoked. 1087 */ setLoggingEventHandler(WifiNative.WifiLoggerEventHandler handler)1088 public boolean setLoggingEventHandler(WifiNative.WifiLoggerEventHandler handler) { 1089 if (handler == null) return false; 1090 synchronized (sLock) { 1091 if (mWifiChip == null) return false; 1092 if (mLogEventHandler != null) return false; 1093 if (!mWifiChip.enableDebugErrorAlerts(true)) { 1094 return false; 1095 } 1096 mLogEventHandler = handler; 1097 return true; 1098 } 1099 } 1100 1101 /** 1102 * Stops all logging and resets the logger callback. 1103 * This stops both the alerts and ring buffer data collection. 1104 * Existing log handler is cleared. 1105 */ resetLogHandler()1106 public boolean resetLogHandler() { 1107 synchronized (sLock) { 1108 mLogEventHandler = null; 1109 if (mWifiChip == null) return false; 1110 if (!mWifiChip.enableDebugErrorAlerts(false)) { 1111 return false; 1112 } 1113 return mWifiChip.stopLoggingToDebugRingBuffer(); 1114 } 1115 } 1116 1117 /** 1118 * Control debug data collection 1119 * 1120 * @param verboseLevel 0 to 3, inclusive. 0 stops logging. 1121 * @param flags Ignored. 1122 * @param maxIntervalInSec Maximum interval between reports; ignore if 0. 1123 * @param minDataSizeInBytes Minimum data size in buffer for report; ignore if 0. 1124 * @param ringName Name of the ring for which data collection is to start. 1125 * @return true for success 1126 */ startLoggingRingBuffer(int verboseLevel, int flags, int maxIntervalInSec, int minDataSizeInBytes, String ringName)1127 public boolean startLoggingRingBuffer(int verboseLevel, int flags, int maxIntervalInSec, 1128 int minDataSizeInBytes, String ringName) { 1129 enter("verboseLevel=%, flags=%, maxIntervalInSec=%, minDataSizeInBytes=%, ringName=%") 1130 .c(verboseLevel).c(flags).c(maxIntervalInSec).c(minDataSizeInBytes).c(ringName) 1131 .flush(); 1132 synchronized (sLock) { 1133 if (mWifiChip == null) return false; 1134 return mWifiChip.startLoggingToDebugRingBuffer( 1135 ringName, 1136 verboseLevel, 1137 maxIntervalInSec, 1138 minDataSizeInBytes 1139 ); 1140 } 1141 } 1142 1143 /** 1144 * Pointlessly fail 1145 * 1146 * @return -1 1147 */ getSupportedLoggerFeatureSet()1148 public int getSupportedLoggerFeatureSet() { 1149 return -1; 1150 } 1151 1152 private String mDriverDescription; // Cached value filled by requestChipDebugInfo() 1153 1154 /** 1155 * Vendor-provided wifi driver version string 1156 */ getDriverVersion()1157 public String getDriverVersion() { 1158 synchronized (sLock) { 1159 if (mDriverDescription == null) requestChipDebugInfo(); 1160 return mDriverDescription; 1161 } 1162 } 1163 1164 private String mFirmwareDescription; // Cached value filled by requestChipDebugInfo() 1165 1166 /** 1167 * Vendor-provided wifi firmware version string 1168 */ getFirmwareVersion()1169 public String getFirmwareVersion() { 1170 synchronized (sLock) { 1171 if (mFirmwareDescription == null) requestChipDebugInfo(); 1172 return mFirmwareDescription; 1173 } 1174 } 1175 1176 /** 1177 * Refreshes our idea of the driver and firmware versions 1178 */ requestChipDebugInfo()1179 private void requestChipDebugInfo() { 1180 mDriverDescription = null; 1181 mFirmwareDescription = null; 1182 synchronized (sLock) { 1183 if (mWifiChip == null) return; 1184 WifiChip.ChipDebugInfo info = mWifiChip.requestChipDebugInfo(); 1185 if (info == null) return; 1186 mDriverDescription = info.driverDescription; 1187 mFirmwareDescription = info.firmwareDescription; 1188 } 1189 mLog.info("Driver: % Firmware: %") 1190 .c(mDriverDescription) 1191 .c(mFirmwareDescription) 1192 .flush(); 1193 } 1194 1195 /** 1196 * API to get the status of all ring buffers supported by driver 1197 */ getRingBufferStatus()1198 public WifiNative.RingBufferStatus[] getRingBufferStatus() { 1199 synchronized (sLock) { 1200 if (mWifiChip == null) return null; 1201 List<WifiNative.RingBufferStatus> statusList = mWifiChip.getDebugRingBuffersStatus(); 1202 if (statusList == null) return null; 1203 1204 WifiNative.RingBufferStatus[] statusArray = 1205 new WifiNative.RingBufferStatus[statusList.size()]; 1206 statusList.toArray(statusArray); 1207 return statusArray; 1208 } 1209 } 1210 1211 /** 1212 * Indicates to driver that all the data has to be uploaded urgently 1213 */ getRingBufferData(String ringName)1214 public boolean getRingBufferData(String ringName) { 1215 enter("ringName %").c(ringName).flush(); 1216 synchronized (sLock) { 1217 if (mWifiChip == null) return false; 1218 return mWifiChip.forceDumpToDebugRingBuffer(ringName); 1219 } 1220 } 1221 1222 /** 1223 * request hal to flush ring buffers to files 1224 */ flushRingBufferData()1225 public boolean flushRingBufferData() { 1226 synchronized (sLock) { 1227 if (mWifiChip == null) return false; 1228 return mWifiChip.flushRingBufferToFile(); 1229 } 1230 } 1231 1232 /** 1233 * Request vendor debug info from the firmware 1234 */ getFwMemoryDump()1235 public byte[] getFwMemoryDump() { 1236 synchronized (sLock) { 1237 if (mWifiChip == null) return null; 1238 return mWifiChip.requestFirmwareDebugDump(); 1239 } 1240 } 1241 1242 /** 1243 * Request vendor debug info from the driver 1244 */ getDriverStateDump()1245 public byte[] getDriverStateDump() { 1246 synchronized (sLock) { 1247 if (mWifiChip == null) return (null); 1248 return mWifiChip.requestDriverDebugDump(); 1249 } 1250 } 1251 1252 /** 1253 * Start packet fate monitoring 1254 * <p> 1255 * Once started, monitoring remains active until HAL is unloaded. 1256 * 1257 * @param ifaceName Name of the interface. 1258 * @return true for success 1259 */ startPktFateMonitoring(@onNull String ifaceName)1260 public boolean startPktFateMonitoring(@NonNull String ifaceName) { 1261 synchronized (sLock) { 1262 WifiStaIface iface = getStaIface(ifaceName); 1263 if (iface == null) return false; 1264 return iface.startDebugPacketFateMonitoring(); 1265 } 1266 } 1267 1268 /** 1269 * Retrieve fates of outbound packets 1270 * <p> 1271 * Reports the outbound frames for the most recent association (space allowing). 1272 * 1273 * @param ifaceName Name of the interface. 1274 * @return list of TxFateReports up to size {@link WifiLoggerHal#MAX_FATE_LOG_LEN}, or empty 1275 * list on failure. 1276 */ getTxPktFates(@onNull String ifaceName)1277 public List<TxFateReport> getTxPktFates(@NonNull String ifaceName) { 1278 synchronized (sLock) { 1279 WifiStaIface iface = getStaIface(ifaceName); 1280 if (iface == null) return new ArrayList<>(); 1281 return iface.getDebugTxPacketFates(); 1282 } 1283 } 1284 1285 /** 1286 * Retrieve fates of inbound packets 1287 * <p> 1288 * Reports the inbound frames for the most recent association (space allowing). 1289 * 1290 * @param ifaceName Name of the interface. 1291 * @return list of RxFateReports up to size {@link WifiLoggerHal#MAX_FATE_LOG_LEN}, or empty 1292 * list on failure. 1293 */ getRxPktFates(@onNull String ifaceName)1294 public List<RxFateReport> getRxPktFates(@NonNull String ifaceName) { 1295 synchronized (sLock) { 1296 WifiStaIface iface = getStaIface(ifaceName); 1297 if (iface == null) return new ArrayList<>(); 1298 return iface.getDebugRxPacketFates(); 1299 } 1300 } 1301 1302 /** 1303 * Start sending the specified keep alive packets periodically. 1304 * 1305 * @param ifaceName Name of the interface. 1306 * @param slot Command ID to use for this invocation. 1307 * @param srcAddr Source MAC address of the packet. 1308 * @param dstAddr Destination MAC address of the packet. 1309 * @param packet IP packet contents to be transmitted. 1310 * @param protocol Ether type to be set in the ethernet frame transmitted. 1311 * @param periodInMs Interval at which this packet must be transmitted. 1312 * @return 0 for success, -1 for error 1313 */ startSendingOffloadedPacket( @onNull String ifaceName, int slot, byte[] srcAddr, byte[] dstAddr, byte[] packet, int protocol, int periodInMs)1314 public int startSendingOffloadedPacket( 1315 @NonNull String ifaceName, int slot, byte[] srcAddr, byte[] dstAddr, 1316 byte[] packet, int protocol, int periodInMs) { 1317 enter("slot=% periodInMs=%").c(slot).c(periodInMs).flush(); 1318 synchronized (sLock) { 1319 WifiStaIface iface = getStaIface(ifaceName); 1320 if (iface == null) return -1; 1321 MacAddress srcMac, dstMac; 1322 try { 1323 srcMac = MacAddress.fromBytes(srcAddr); 1324 dstMac = MacAddress.fromBytes(dstAddr); 1325 } catch (IllegalArgumentException e) { 1326 mLog.info("Invalid MacAddress in startSendingOffloadedPacket").flush(); 1327 return -1; 1328 } 1329 boolean success = iface.startSendingKeepAlivePackets( 1330 slot, 1331 packet, 1332 (short) protocol, 1333 srcMac, 1334 dstMac, 1335 periodInMs); 1336 return success ? 0 : -1; 1337 } 1338 } 1339 1340 /** 1341 * Stop sending the specified keep alive packets. 1342 * 1343 * @param ifaceName Name of the interface. 1344 * @param slot id - same as startSendingOffloadedPacket call. 1345 * @return 0 for success, -1 for error 1346 */ stopSendingOffloadedPacket(@onNull String ifaceName, int slot)1347 public int stopSendingOffloadedPacket(@NonNull String ifaceName, int slot) { 1348 enter("slot=%").c(slot).flush(); 1349 1350 synchronized (sLock) { 1351 WifiStaIface iface = getStaIface(ifaceName); 1352 if (iface == null) return -1; 1353 boolean success = iface.stopSendingKeepAlivePackets(slot); 1354 return success ? 0 : -1; 1355 } 1356 } 1357 1358 /** 1359 * A fixed cmdId for our RssiMonitoring (we only do one at a time) 1360 */ 1361 @VisibleForTesting 1362 static final int sRssiMonCmdId = 7551; 1363 1364 /** 1365 * Our client's handler 1366 */ 1367 private WifiNative.WifiRssiEventHandler mWifiRssiEventHandler; 1368 1369 /** 1370 * Start RSSI monitoring on the currently connected access point. 1371 * 1372 * @param ifaceName Name of the interface. 1373 * @param maxRssi Maximum RSSI threshold. 1374 * @param minRssi Minimum RSSI threshold. 1375 * @param rssiEventHandler Called when RSSI goes above maxRssi or below minRssi 1376 * @return 0 for success, -1 for failure 1377 */ startRssiMonitoring(@onNull String ifaceName, byte maxRssi, byte minRssi, WifiNative.WifiRssiEventHandler rssiEventHandler)1378 public int startRssiMonitoring(@NonNull String ifaceName, byte maxRssi, byte minRssi, 1379 WifiNative.WifiRssiEventHandler rssiEventHandler) { 1380 enter("maxRssi=% minRssi=%").c(maxRssi).c(minRssi).flush(); 1381 if (maxRssi <= minRssi) return -1; 1382 if (rssiEventHandler == null) return -1; 1383 synchronized (sLock) { 1384 WifiStaIface iface = getStaIface(ifaceName); 1385 if (iface == null) return -1; 1386 iface.stopRssiMonitoring(sRssiMonCmdId); 1387 if (!iface.startRssiMonitoring(sRssiMonCmdId, maxRssi, minRssi)) return -1; 1388 mWifiRssiEventHandler = rssiEventHandler; 1389 return 0; 1390 } 1391 } 1392 1393 /** 1394 * Stop RSSI monitoring 1395 * 1396 * @param ifaceName Name of the interface. 1397 * @return 0 for success, -1 for failure 1398 */ stopRssiMonitoring(@onNull String ifaceName)1399 public int stopRssiMonitoring(@NonNull String ifaceName) { 1400 synchronized (sLock) { 1401 mWifiRssiEventHandler = null; 1402 WifiStaIface iface = getStaIface(ifaceName); 1403 if (iface == null) return -1; 1404 boolean success = iface.stopRssiMonitoring(sRssiMonCmdId); 1405 return success ? 0 : -1; 1406 } 1407 } 1408 1409 /** 1410 * Fetch the host wakeup reasons stats from wlan driver. 1411 * 1412 * @return the |WlanWakeReasonAndCounts| from the wlan driver, or null on failure. 1413 */ getWlanWakeReasonCount()1414 public WlanWakeReasonAndCounts getWlanWakeReasonCount() { 1415 synchronized (sLock) { 1416 if (mWifiChip == null) return null; 1417 return mWifiChip.getDebugHostWakeReasonStats(); 1418 } 1419 } 1420 1421 /** 1422 * Enable/Disable Neighbour discovery offload functionality in the firmware. 1423 * 1424 * @param ifaceName Name of the interface. 1425 * @param enabled true to enable, false to disable. 1426 * @return true for success, false for failure 1427 */ configureNeighborDiscoveryOffload(@onNull String ifaceName, boolean enabled)1428 public boolean configureNeighborDiscoveryOffload(@NonNull String ifaceName, boolean enabled) { 1429 enter("enabled=%").c(enabled).flush(); 1430 synchronized (sLock) { 1431 WifiStaIface iface = getStaIface(ifaceName); 1432 if (iface == null) return false; 1433 return iface.enableNdOffload(enabled); 1434 } 1435 } 1436 1437 // Firmware roaming control. 1438 1439 /** 1440 * Query the firmware roaming capabilities. 1441 * 1442 * @param ifaceName Name of the interface. 1443 * @return capabilities object on success, null otherwise. 1444 */ 1445 @Nullable getRoamingCapabilities(@onNull String ifaceName)1446 public WifiNative.RoamingCapabilities getRoamingCapabilities(@NonNull String ifaceName) { 1447 synchronized (sLock) { 1448 WifiStaIface iface = getStaIface(ifaceName); 1449 if (iface == null) return null; 1450 return iface.getRoamingCapabilities(); 1451 } 1452 } 1453 1454 /** 1455 * Enable/disable firmware roaming. 1456 * 1457 * @param ifaceName Name of the interface. 1458 * @param state the intended roaming state 1459 * @return SET_FIRMWARE_ROAMING_SUCCESS, SET_FIRMWARE_ROAMING_FAILURE, 1460 * or SET_FIRMWARE_ROAMING_BUSY 1461 */ enableFirmwareRoaming(@onNull String ifaceName, @WifiNative.RoamingEnableState int state)1462 public @WifiNative.RoamingEnableStatus int enableFirmwareRoaming(@NonNull String ifaceName, 1463 @WifiNative.RoamingEnableState int state) { 1464 synchronized (sLock) { 1465 WifiStaIface iface = getStaIface(ifaceName); 1466 if (iface == null) return WifiNative.SET_FIRMWARE_ROAMING_FAILURE; 1467 return iface.setRoamingState(state); 1468 } 1469 } 1470 1471 /** 1472 * Set firmware roaming configurations. 1473 * 1474 * @param ifaceName Name of the interface. 1475 * @param config new roaming configuration object 1476 * @return true for success; false for failure 1477 */ configureRoaming(@onNull String ifaceName, WifiNative.RoamingConfig config)1478 public boolean configureRoaming(@NonNull String ifaceName, WifiNative.RoamingConfig config) { 1479 synchronized (sLock) { 1480 WifiStaIface iface = getStaIface(ifaceName); 1481 if (iface == null) return false; 1482 try { 1483 // parse the blocklist BSSIDs if any 1484 List<MacAddress> bssidBlocklist = new ArrayList<>(); 1485 if (config.blocklistBssids != null) { 1486 for (String bssid : config.blocklistBssids) { 1487 bssidBlocklist.add(MacAddress.fromString(bssid)); 1488 } 1489 } 1490 1491 // parse the allowlist SSIDs if any 1492 List<byte[]> ssidAllowlist = new ArrayList<>(); 1493 if (config.allowlistSsids != null) { 1494 for (String ssidStr : config.allowlistSsids) { 1495 for (WifiSsid originalSsid : mSsidTranslator.getAllPossibleOriginalSsids( 1496 WifiSsid.fromString(ssidStr))) { 1497 // HIDL code is throwing InvalidArgumentException when ssidWhitelist has 1498 // SSIDs with less than 32 byte length this is due to HAL definition of 1499 // SSID declared it as 32-byte fixed length array. Thus pad additional 1500 // bytes with 0's to pass SSIDs as byte arrays of 32 length 1501 ssidAllowlist.add( 1502 Arrays.copyOf(originalSsid.getBytes(), 32)); 1503 } 1504 } 1505 } 1506 1507 return iface.configureRoaming(bssidBlocklist, ssidAllowlist); 1508 } catch (IllegalArgumentException e) { 1509 mLog.err("Illegal argument for roaming configuration").c(e.toString()).flush(); 1510 return false; 1511 } 1512 } 1513 } 1514 1515 /** 1516 * Select one of the pre-configured TX power level scenarios or reset it back to normal. 1517 * Primarily used for meeting SAR requirements during voice calls. 1518 * 1519 * Note: If it was found out that the scenario to be reported is the same as last reported one, 1520 * then exit with success. 1521 * This is to handle the case when some HAL versions deal with different inputs equally, 1522 * in that case, we should not call the hal unless there is a change in scenario. 1523 * Note: It is assumed that this method is only called if SAR is enabled. The logic of whether 1524 * to call it or not resides in SarManager class. 1525 * 1526 * @param sarInfo The collection of inputs to select the SAR scenario. 1527 * @return true for success; false for failure or if the HAL version does not support this API. 1528 */ selectTxPowerScenario(SarInfo sarInfo)1529 public boolean selectTxPowerScenario(SarInfo sarInfo) { 1530 synchronized (sLock) { 1531 if (mWifiChip == null) return false; 1532 return mWifiChip.selectTxPowerScenario(sarInfo); 1533 } 1534 } 1535 1536 /** 1537 * Enable/Disable low-latency mode 1538 * 1539 * @param enabled true to enable low-latency mode, false to disable it 1540 */ setLowLatencyMode(boolean enabled)1541 public boolean setLowLatencyMode(boolean enabled) { 1542 synchronized (sLock) { 1543 if (mWifiChip == null) return false; 1544 return mWifiChip.setLowLatencyMode(enabled); 1545 } 1546 } 1547 1548 /** 1549 * Returns whether the given HdmIfaceTypeForCreation combo is supported or not. 1550 */ canDeviceSupportCreateTypeCombo(SparseArray<Integer> combo)1551 public boolean canDeviceSupportCreateTypeCombo(SparseArray<Integer> combo) { 1552 synchronized (sLock) { 1553 return mHalDeviceManager.canDeviceSupportCreateTypeCombo(combo); 1554 } 1555 } 1556 1557 /** 1558 * Returns whether a new iface can be created without tearing down any existing ifaces. 1559 */ canDeviceSupportAdditionalIface( @alDeviceManager.HdmIfaceTypeForCreation int createIfaceType, @NonNull WorkSource requestorWs)1560 public boolean canDeviceSupportAdditionalIface( 1561 @HalDeviceManager.HdmIfaceTypeForCreation int createIfaceType, 1562 @NonNull WorkSource requestorWs) { 1563 synchronized (sLock) { 1564 List<Pair<Integer, WorkSource>> creationImpact = 1565 mHalDeviceManager.reportImpactToCreateIface(createIfaceType, true, requestorWs); 1566 return creationImpact != null && creationImpact.isEmpty(); 1567 } 1568 } 1569 1570 /** 1571 * Returns whether STA + AP concurrency is supported or not. 1572 */ isStaApConcurrencySupported()1573 public boolean isStaApConcurrencySupported() { 1574 synchronized (sLock) { 1575 return mHalDeviceManager.canDeviceSupportCreateTypeCombo(new SparseArray<Integer>() {{ 1576 put(HDM_CREATE_IFACE_STA, 1); 1577 put(HDM_CREATE_IFACE_AP, 1); 1578 }}); 1579 } 1580 } 1581 1582 /** 1583 * Returns whether STA + STA concurrency is supported or not. 1584 */ 1585 public boolean isStaStaConcurrencySupported() { 1586 synchronized (sLock) { 1587 return mHalDeviceManager.canDeviceSupportCreateTypeCombo(new SparseArray<Integer>() {{ 1588 put(HDM_CREATE_IFACE_STA, 2); 1589 }}); 1590 } 1591 } 1592 1593 /** 1594 * Returns whether a new AP iface can be created or not. 1595 */ 1596 public boolean isItPossibleToCreateApIface(@NonNull WorkSource requestorWs) { 1597 synchronized (sLock) { 1598 return mHalDeviceManager.isItPossibleToCreateIface(HDM_CREATE_IFACE_AP, requestorWs); 1599 } 1600 } 1601 1602 /** 1603 * Returns whether a new AP iface can be created or not. 1604 */ 1605 public boolean isItPossibleToCreateBridgedApIface(@NonNull WorkSource requestorWs) { 1606 synchronized (sLock) { 1607 return mHalDeviceManager.isItPossibleToCreateIface( 1608 HDM_CREATE_IFACE_AP_BRIDGE, requestorWs); 1609 } 1610 } 1611 1612 /** 1613 * Returns whether a new STA iface can be created or not. 1614 */ 1615 public boolean isItPossibleToCreateStaIface(@NonNull WorkSource requestorWs) { 1616 synchronized (sLock) { 1617 return mHalDeviceManager.isItPossibleToCreateIface(HDM_CREATE_IFACE_STA, requestorWs); 1618 } 1619 1620 } 1621 /** 1622 * Set primary connection when multiple STA ifaces are active. 1623 * 1624 * @param ifaceName Name of the interface. 1625 * @return true for success 1626 */ 1627 public boolean setMultiStaPrimaryConnection(@NonNull String ifaceName) { 1628 if (TextUtils.isEmpty(ifaceName)) return false; 1629 synchronized (sLock) { 1630 if (mWifiChip == null) return false; 1631 return mWifiChip.setMultiStaPrimaryConnection(ifaceName); 1632 } 1633 } 1634 1635 /** 1636 * Set use-case when multiple STA ifaces are active. 1637 * 1638 * @param useCase one of the use cases. 1639 * @return true for success 1640 */ 1641 public boolean setMultiStaUseCase(@WifiNative.MultiStaUseCase int useCase) { 1642 synchronized (sLock) { 1643 if (mWifiChip == null) return false; 1644 return mWifiChip.setMultiStaUseCase(useCase); 1645 } 1646 } 1647 1648 /** 1649 * Notify scan mode state to driver to save power in scan-only mode. 1650 * 1651 * @param ifaceName Name of the interface. 1652 * @param enable whether is in scan-only mode 1653 * @return true for success 1654 */ 1655 public boolean setScanMode(@NonNull String ifaceName, boolean enable) { 1656 synchronized (sLock) { 1657 WifiStaIface iface = getStaIface(ifaceName); 1658 if (iface == null) return false; 1659 return iface.setScanMode(enable); 1660 } 1661 } 1662 1663 /** 1664 * Callback for events on the STA interface. 1665 */ 1666 private class StaIfaceEventCallback implements WifiStaIface.Callback { 1667 @Override 1668 public void onBackgroundScanFailure(int cmdId) { 1669 mVerboseLog.d("onBackgroundScanFailure " + cmdId); 1670 WifiNative.ScanEventHandler eventHandler; 1671 synchronized (sLock) { 1672 if (mScan == null || cmdId != mScan.cmdId) return; 1673 eventHandler = mScan.eventHandler; 1674 } 1675 eventHandler.onScanStatus(WifiNative.WIFI_SCAN_FAILED); 1676 } 1677 1678 @Override 1679 public void onBackgroundFullScanResult( 1680 int cmdId, int bucketsScanned, ScanResult result) { 1681 mVerboseLog.d("onBackgroundFullScanResult " + cmdId); 1682 WifiNative.ScanEventHandler eventHandler; 1683 synchronized (sLock) { 1684 if (mScan == null || cmdId != mScan.cmdId) return; 1685 eventHandler = mScan.eventHandler; 1686 } 1687 eventHandler.onFullScanResult(result, bucketsScanned); 1688 } 1689 1690 @Override 1691 public void onBackgroundScanResults(int cmdId, WifiScanner.ScanData[] scanDatas) { 1692 mVerboseLog.d("onBackgroundScanResults " + cmdId); 1693 WifiNative.ScanEventHandler eventHandler; 1694 // WifiScanner currently uses the results callback to fetch the scan results. 1695 // So, simulate that by sending out the notification and then caching the results 1696 // locally. This will then be returned to WifiScanner via getScanResults. 1697 synchronized (sLock) { 1698 if (mScan == null || cmdId != mScan.cmdId) return; 1699 eventHandler = mScan.eventHandler; 1700 mScan.latestScanResults = scanDatas; 1701 } 1702 eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); 1703 } 1704 1705 @Override 1706 public void onRssiThresholdBreached(int cmdId, byte[/* 6 */] currBssid, int currRssi) { 1707 mVerboseLog.d("onRssiThresholdBreached " + cmdId + "currRssi " + currRssi); 1708 WifiNative.WifiRssiEventHandler eventHandler; 1709 synchronized (sLock) { 1710 if (mWifiRssiEventHandler == null || cmdId != sRssiMonCmdId) return; 1711 eventHandler = mWifiRssiEventHandler; 1712 } 1713 eventHandler.onRssiThresholdBreached((byte) currRssi); 1714 } 1715 } 1716 1717 /** 1718 * Callback for events on the chip. 1719 */ 1720 private class ChipEventCallback implements WifiChip.Callback { 1721 @Override 1722 public void onChipReconfigured(int modeId) { 1723 mVerboseLog.d("onChipReconfigured " + modeId); 1724 } 1725 1726 @Override 1727 public void onChipReconfigureFailure(int status) { 1728 mVerboseLog.d("onChipReconfigureFailure " + status); 1729 } 1730 1731 public void onIfaceAdded(int type, String name) { 1732 mVerboseLog.d("onIfaceAdded " + type + ", name: " + name); 1733 } 1734 1735 @Override 1736 public void onIfaceRemoved(int type, String name) { 1737 mVerboseLog.d("onIfaceRemoved " + type + ", name: " + name); 1738 } 1739 1740 @Override 1741 public void onDebugRingBufferDataAvailable( 1742 WifiNative.RingBufferStatus status, byte[] data) { 1743 mHalEventHandler.post(() -> { 1744 WifiNative.WifiLoggerEventHandler eventHandler; 1745 synchronized (sLock) { 1746 if (mLogEventHandler == null || status == null || data == null) return; 1747 eventHandler = mLogEventHandler; 1748 } 1749 // Because |sLock| has been released, there is a chance that we'll execute 1750 // a spurious callback (after someone has called resetLogHandler()). 1751 // 1752 // However, the alternative risks deadlock. Consider: 1753 // [T1.1] WifiDiagnostics.captureBugReport() 1754 // [T1.2] -- acquire WifiDiagnostics object's intrinsic lock 1755 // [T1.3] -> WifiVendorHal.getRingBufferData() 1756 // [T1.4] -- acquire WifiVendorHal.sLock 1757 // [T2.1] <lambda>() 1758 // [T2.2] -- acquire WifiVendorHal.sLock 1759 // [T2.3] -> WifiDiagnostics.onRingBufferData() 1760 // [T2.4] -- acquire WifiDiagnostics object's intrinsic lock 1761 // 1762 // The problem here is that the two threads acquire the locks in opposite order. 1763 // If, for example, T2.2 executes between T1.2 and 1.4, then T1 and T2 1764 // will be deadlocked. 1765 int sizeBefore = data.length; 1766 boolean conversionFailure = false; 1767 try { 1768 eventHandler.onRingBufferData(status, data); 1769 int sizeAfter = data.length; 1770 if (sizeAfter != sizeBefore) { 1771 conversionFailure = true; 1772 } 1773 } catch (ArrayIndexOutOfBoundsException e) { 1774 conversionFailure = true; 1775 } 1776 if (conversionFailure) { 1777 Log.wtf("WifiVendorHal", "Conversion failure detected in " 1778 + "onDebugRingBufferDataAvailable. " 1779 + "The input ArrayList |data| is potentially corrupted. " 1780 + "Starting size=" + sizeBefore + ", " 1781 + "final size=" + data.length); 1782 } 1783 }); 1784 } 1785 1786 @Override 1787 public void onDebugErrorAlert(int errorCode, byte[] debugData) { 1788 mLog.w("onDebugErrorAlert " + errorCode); 1789 mHalEventHandler.post(() -> { 1790 WifiNative.WifiLoggerEventHandler eventHandler; 1791 synchronized (sLock) { 1792 if (mLogEventHandler == null || debugData == null) return; 1793 eventHandler = mLogEventHandler; 1794 } 1795 // See comment in onDebugRingBufferDataAvailable(), for an explanation 1796 // of why this callback is invoked without |sLock| held. 1797 eventHandler.onWifiAlert(errorCode, debugData); 1798 }); 1799 } 1800 1801 @Override 1802 public void onRadioModeChange(List<WifiChip.RadioModeInfo> radioModeInfoList) { 1803 mVerboseLog.d("onRadioModeChange " + radioModeInfoList); 1804 WifiNative.VendorHalRadioModeChangeEventHandler handler; 1805 synchronized (sLock) { 1806 if (mRadioModeChangeEventHandler == null || radioModeInfoList == null) return; 1807 handler = mRadioModeChangeEventHandler; 1808 } 1809 // Should only contain 1 or 2 radio infos. 1810 if (radioModeInfoList.size() == 0 || radioModeInfoList.size() > 2) { 1811 mLog.e("Unexpected number of radio info in list " + radioModeInfoList.size()); 1812 return; 1813 } 1814 WifiChip.RadioModeInfo radioModeInfo0 = radioModeInfoList.get(0); 1815 WifiChip.RadioModeInfo radioModeInfo1 = 1816 radioModeInfoList.size() == 2 ? radioModeInfoList.get(1) : null; 1817 // Number of ifaces on each radio should be equal. 1818 if (radioModeInfo1 != null 1819 && radioModeInfo0.ifaceInfos.size() != radioModeInfo1.ifaceInfos.size()) { 1820 mLog.e("Unexpected number of iface info in list " 1821 + radioModeInfo0.ifaceInfos.size() + ", " 1822 + radioModeInfo1.ifaceInfos.size()); 1823 return; 1824 } 1825 int numIfacesOnEachRadio = radioModeInfo0.ifaceInfos.size(); 1826 // Only 1 or 2 ifaces should be present on each radio. 1827 if (numIfacesOnEachRadio == 0 || numIfacesOnEachRadio > 2) { 1828 mLog.e("Unexpected number of iface info in list " + numIfacesOnEachRadio); 1829 return; 1830 } 1831 Runnable runnable = null; 1832 // 2 ifaces simultaneous on 2 radios. 1833 if (radioModeInfoList.size() == 2 && numIfacesOnEachRadio == 1) { 1834 // Iface on radio0 should be different from the iface on radio1 for DBS & SBS. 1835 if (areSameIfaceNames(radioModeInfo0.ifaceInfos, radioModeInfo1.ifaceInfos)) { 1836 mLog.e("Unexpected for both radio infos to have same iface"); 1837 return; 1838 } 1839 if (radioModeInfo0.bandInfo != radioModeInfo1.bandInfo) { 1840 runnable = () -> { 1841 handler.onDbs(); 1842 }; 1843 } else { 1844 runnable = () -> { 1845 handler.onSbs(radioModeInfo0.bandInfo); 1846 }; 1847 } 1848 // 2 ifaces time sharing on 1 radio. 1849 } else if (radioModeInfoList.size() == 1 && numIfacesOnEachRadio == 2) { 1850 WifiChip.IfaceInfo ifaceInfo0 = radioModeInfo0.ifaceInfos.get(0); 1851 WifiChip.IfaceInfo ifaceInfo1 = radioModeInfo0.ifaceInfos.get(1); 1852 if (ifaceInfo0.channel != ifaceInfo1.channel) { 1853 runnable = () -> { 1854 handler.onMcc(radioModeInfo0.bandInfo); 1855 }; 1856 } else { 1857 runnable = () -> { 1858 handler.onScc(radioModeInfo0.bandInfo); 1859 }; 1860 } 1861 } else { 1862 // Not concurrency scenario, uninteresting... 1863 } 1864 if (runnable != null) mHalEventHandler.post(runnable); 1865 } 1866 } 1867 1868 private boolean areSameIfaceNames(List<WifiChip.IfaceInfo> ifaceList1, 1869 List<WifiChip.IfaceInfo> ifaceList2) { 1870 List<String> ifaceNamesList1 = ifaceList1 1871 .stream() 1872 .map(i -> i.name) 1873 .collect(Collectors.toList()); 1874 List<String> ifaceNamesList2 = ifaceList2 1875 .stream() 1876 .map(i -> i.name) 1877 .collect(Collectors.toList()); 1878 return ifaceNamesList1.containsAll(ifaceNamesList2); 1879 } 1880 1881 /** 1882 * Hal Device Manager callbacks. 1883 */ 1884 public class HalDeviceManagerStatusListener implements HalDeviceManager.ManagerStatusListener { 1885 @Override 1886 public void onStatusChanged() { 1887 boolean isReady = mHalDeviceManager.isReady(); 1888 boolean isStarted = mHalDeviceManager.isStarted(); 1889 1890 mVerboseLog.i("Device Manager onStatusChanged. isReady(): " + isReady 1891 + ", isStarted(): " + isStarted); 1892 if (!isReady) { 1893 // Probably something unpleasant, e.g. the server died 1894 WifiNative.VendorHalDeathEventHandler handler; 1895 synchronized (sLock) { 1896 clearState(); 1897 handler = mDeathEventHandler; 1898 } 1899 if (handler != null) { 1900 handler.onDeath(); 1901 } 1902 } 1903 } 1904 } 1905 1906 /** 1907 * Trigger subsystem restart in vendor side 1908 */ 1909 public boolean startSubsystemRestart() { 1910 synchronized (sLock) { 1911 if (mWifiChip == null) return false; 1912 return mWifiChip.triggerSubsystemRestart(); 1913 } 1914 } 1915 1916 /** 1917 * Retrieve the list of usable Wifi channels. 1918 */ 1919 public List<WifiAvailableChannel> getUsableChannels( 1920 @WifiScanner.WifiBand int band, 1921 @WifiAvailableChannel.OpMode int mode, 1922 @WifiAvailableChannel.Filter int filter) { 1923 synchronized (sLock) { 1924 if (mWifiChip == null) return null; 1925 return mWifiChip.getUsableChannels(band, mode, filter); 1926 } 1927 } 1928 1929 /** 1930 * Set maximum acceptable DTIM multiplier to hardware driver. Any multiplier larger than the 1931 * maximum value must not be accepted, it will cause packet loss higher than what the system 1932 * can accept, which will cause unexpected behavior for apps, and may interrupt the network 1933 * connection. 1934 * 1935 * @param ifaceName Name of the interface. 1936 * @param multiplier integer maximum DTIM multiplier value to set. 1937 * @return true for success 1938 */ 1939 public boolean setDtimMultiplier(@NonNull String ifaceName, int multiplier) { 1940 synchronized (sLock) { 1941 WifiStaIface iface = getStaIface(ifaceName); 1942 if (iface == null) return false; 1943 return iface.setDtimMultiplier(multiplier); 1944 } 1945 } 1946 1947 /** 1948 * Set the Multi-Link Operation mode. 1949 * 1950 * @param mode Multi-Link operation mode {@link android.net.wifi.WifiManager.MloMode}. 1951 * @return {@code true} if success, otherwise {@code false}. 1952 */ 1953 public @WifiStatusCode int setMloMode(@WifiManager.MloMode int mode) { 1954 synchronized (sLock) { 1955 if (mWifiChip == null) return WifiStatusCode.ERROR_WIFI_CHIP_INVALID; 1956 return mWifiChip.setMloMode(mode); 1957 } 1958 } 1959 1960 /** 1961 * Enable/disable the feature of allowing current STA-connected channel for WFA GO, SAP and 1962 * Aware when the regulatory allows. 1963 * 1964 * @param enableIndoorChannel enable or disable indoor channel. 1965 * @param enableDfsChannel enable or disable DFS channel. 1966 * @return true if the operation succeeded, false if there is an error in Hal. 1967 */ 1968 public boolean enableStaChannelForPeerNetwork(boolean enableIndoorChannel, 1969 boolean enableDfsChannel) { 1970 synchronized (sLock) { 1971 if (mWifiChip == null) return false; 1972 return mWifiChip.enableStaChannelForPeerNetwork(enableIndoorChannel, enableDfsChannel); 1973 } 1974 } 1975 1976 /** 1977 * See {@link WifiNative#isBandCombinationSupported(String, List)}. 1978 */ 1979 public boolean isBandCombinationSupported(@NonNull String ifaceName, 1980 @NonNull List<Integer> bands) { 1981 synchronized (sLock) { 1982 WifiStaIface iface = getStaIface(ifaceName); 1983 if (iface == null) return false; 1984 return mHalDeviceManager.isBandCombinationSupported(iface, bands); 1985 } 1986 } 1987 1988 /** 1989 * See {@link WifiNative#getSupportedBandCombinations(String)}. 1990 */ 1991 public Set<List<Integer>> getSupportedBandCombinations(String ifaceName) { 1992 synchronized (sLock) { 1993 WifiStaIface iface = getStaIface(ifaceName); 1994 if (iface == null) return null; 1995 return mHalDeviceManager.getSupportedBandCombinations(iface); 1996 } 1997 } 1998 } 1999