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