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