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 android.net.wifi.CoexUnsafeChannel.POWER_CAP_NONE; 19 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.content.Context; 23 import android.content.pm.PackageManager; 24 import android.hardware.wifi.V1_0.IWifiApIface; 25 import android.hardware.wifi.V1_0.IWifiChip; 26 import android.hardware.wifi.V1_0.IWifiChipEventCallback; 27 import android.hardware.wifi.V1_0.IWifiIface; 28 import android.hardware.wifi.V1_0.IWifiStaIface; 29 import android.hardware.wifi.V1_0.IWifiStaIfaceEventCallback; 30 import android.hardware.wifi.V1_0.IfaceType; 31 import android.hardware.wifi.V1_0.StaBackgroundScanBucketEventReportSchemeMask; 32 import android.hardware.wifi.V1_0.StaBackgroundScanBucketParameters; 33 import android.hardware.wifi.V1_0.StaBackgroundScanParameters; 34 import android.hardware.wifi.V1_0.StaLinkLayerIfaceStats; 35 import android.hardware.wifi.V1_0.StaLinkLayerRadioStats; 36 import android.hardware.wifi.V1_0.StaLinkLayerStats; 37 import android.hardware.wifi.V1_0.StaRoamingConfig; 38 import android.hardware.wifi.V1_0.StaRoamingState; 39 import android.hardware.wifi.V1_0.StaScanData; 40 import android.hardware.wifi.V1_0.StaScanDataFlagMask; 41 import android.hardware.wifi.V1_0.StaScanResult; 42 import android.hardware.wifi.V1_0.WifiDebugHostWakeReasonStats; 43 import android.hardware.wifi.V1_0.WifiDebugPacketFateFrameType; 44 import android.hardware.wifi.V1_0.WifiDebugRingBufferFlags; 45 import android.hardware.wifi.V1_0.WifiDebugRingBufferStatus; 46 import android.hardware.wifi.V1_0.WifiDebugRxPacketFate; 47 import android.hardware.wifi.V1_0.WifiDebugRxPacketFateReport; 48 import android.hardware.wifi.V1_0.WifiDebugTxPacketFate; 49 import android.hardware.wifi.V1_0.WifiDebugTxPacketFateReport; 50 import android.hardware.wifi.V1_0.WifiInformationElement; 51 import android.hardware.wifi.V1_0.WifiStatus; 52 import android.hardware.wifi.V1_0.WifiStatusCode; 53 import android.hardware.wifi.V1_2.IWifiChipEventCallback.IfaceInfo; 54 import android.hardware.wifi.V1_5.IWifiChip.MultiStaUseCase; 55 import android.hardware.wifi.V1_5.IWifiChip.UsableChannelFilter; 56 import android.hardware.wifi.V1_5.StaPeerInfo; 57 import android.hardware.wifi.V1_5.StaRateStat; 58 import android.hardware.wifi.V1_5.WifiBand; 59 import android.hardware.wifi.V1_5.WifiIfaceMode; 60 import android.hardware.wifi.V1_5.WifiUsableChannel; 61 import android.net.MacAddress; 62 import android.net.apf.ApfCapabilities; 63 import android.net.wifi.ScanResult; 64 import android.net.wifi.SoftApConfiguration; 65 import android.net.wifi.WifiAvailableChannel; 66 import android.net.wifi.WifiManager; 67 import android.net.wifi.WifiScanner; 68 import android.net.wifi.WifiSsid; 69 import android.os.Handler; 70 import android.os.RemoteException; 71 import android.os.WorkSource; 72 import android.text.TextUtils; 73 import android.util.Log; 74 import android.util.Pair; 75 import android.util.SparseArray; 76 77 import com.android.internal.annotations.VisibleForTesting; 78 import com.android.internal.util.HexDump; 79 import com.android.modules.utils.build.SdkLevel; 80 import com.android.server.wifi.HalDeviceManager.InterfaceDestroyedListener; 81 import com.android.server.wifi.WifiLinkLayerStats.ChannelStats; 82 import com.android.server.wifi.WifiLinkLayerStats.PeerInfo; 83 import com.android.server.wifi.WifiLinkLayerStats.RadioStat; 84 import com.android.server.wifi.WifiLinkLayerStats.RateStat; 85 import com.android.server.wifi.WifiNative.RxFateReport; 86 import com.android.server.wifi.WifiNative.TxFateReport; 87 import com.android.server.wifi.util.BitMask; 88 import com.android.server.wifi.util.GeneralUtil.Mutable; 89 import com.android.server.wifi.util.NativeUtil; 90 import com.android.wifi.resources.R; 91 92 import com.google.errorprone.annotations.CompileTimeConstant; 93 94 import java.util.ArrayList; 95 import java.util.HashMap; 96 import java.util.List; 97 import java.util.Set; 98 import java.util.stream.Collectors; 99 100 /** 101 * Vendor HAL via HIDL 102 */ 103 public class WifiVendorHal { 104 105 private static final WifiLog sNoLog = new FakeWifiLog(); 106 107 /** 108 * Chatty logging should use mVerboseLog 109 */ 110 @VisibleForTesting 111 WifiLog mVerboseLog = sNoLog; 112 113 /** 114 * Errors should use mLog 115 */ 116 @VisibleForTesting 117 WifiLog mLog = new LogcatLog("WifiVendorHal"); 118 119 /** 120 * Enables or disables verbose logging 121 * 122 * @param verbose - with the obvious interpretation 123 */ enableVerboseLogging(boolean verbose)124 public void enableVerboseLogging(boolean verbose) { 125 synchronized (sLock) { 126 if (verbose) { 127 mVerboseLog = mLog; 128 enter("verbose=true").flush(); 129 } else { 130 enter("verbose=false").flush(); 131 mVerboseLog = sNoLog; 132 } 133 } 134 } 135 136 /** 137 * Checks for a successful status result. 138 * 139 * Failures are logged to mLog. 140 * 141 * @param status is the WifiStatus generated by a hal call 142 * @return true for success, false for failure 143 */ ok(WifiStatus status)144 private boolean ok(WifiStatus status) { 145 if (status.code == WifiStatusCode.SUCCESS) return true; 146 147 Thread cur = Thread.currentThread(); 148 StackTraceElement[] trace = cur.getStackTrace(); 149 150 mLog.err("% failed %") 151 .c(niceMethodName(trace, 3)) 152 .c(status.toString()) 153 .flush(); 154 155 return false; 156 } 157 158 /** 159 * Logs the argument along with the method name. 160 * 161 * Always returns its argument. 162 */ boolResult(boolean result)163 private boolean boolResult(boolean result) { 164 if (mVerboseLog == sNoLog) return result; 165 // Currently only seen if verbose logging is on 166 167 Thread cur = Thread.currentThread(); 168 StackTraceElement[] trace = cur.getStackTrace(); 169 170 mVerboseLog.err("% returns %") 171 .c(niceMethodName(trace, 3)) 172 .c(result) 173 .flush(); 174 175 return result; 176 } 177 objResult(T obj)178 private <T> T objResult(T obj) { 179 if (mVerboseLog == sNoLog) return obj; 180 // Currently only seen if verbose logging is on 181 182 Thread cur = Thread.currentThread(); 183 StackTraceElement[] trace = cur.getStackTrace(); 184 185 mVerboseLog.err("% returns %") 186 .c(niceMethodName(trace, 3)) 187 .c(String.valueOf(obj)) 188 .flush(); 189 190 return obj; 191 } 192 193 /** 194 * Logs the argument along with the method name. 195 * 196 * Always returns its argument. 197 */ nullResult()198 private <T> T nullResult() { 199 if (mVerboseLog == sNoLog) return null; 200 // Currently only seen if verbose logging is on 201 202 Thread cur = Thread.currentThread(); 203 StackTraceElement[] trace = cur.getStackTrace(); 204 205 mVerboseLog.err("% returns %") 206 .c(niceMethodName(trace, 3)) 207 .c(null) 208 .flush(); 209 210 return null; 211 } 212 213 /** 214 * Logs the argument along with the method name. 215 * 216 * Always returns its argument. 217 */ byteArrayResult(byte[] result)218 private byte[] byteArrayResult(byte[] result) { 219 if (mVerboseLog == sNoLog) return result; 220 // Currently only seen if verbose logging is on 221 222 Thread cur = Thread.currentThread(); 223 StackTraceElement[] trace = cur.getStackTrace(); 224 225 mVerboseLog.err("% returns %") 226 .c(niceMethodName(trace, 3)) 227 .c(result == null ? "(null)" : HexDump.dumpHexString(result)) 228 .flush(); 229 230 return result; 231 } 232 233 /** 234 * Logs at method entry 235 * 236 * @param format string with % placeholders 237 * @return LogMessage formatter (remember to .flush()) 238 */ enter(@ompileTimeConstant final String format)239 private WifiLog.LogMessage enter(@CompileTimeConstant final String format) { 240 if (mVerboseLog == sNoLog) return sNoLog.info(format); 241 return mVerboseLog.trace(format, 1); 242 } 243 244 /** 245 * Gets the method name and line number from a stack trace. 246 * 247 * Attempts to skip frames created by lambdas to get a human-sensible name. 248 * 249 * @param trace, fo example obtained by Thread.currentThread().getStackTrace() 250 * @param start frame number to log, typically 3 251 * @return string containing the method name and line number 252 */ niceMethodName(StackTraceElement[] trace, int start)253 private static String niceMethodName(StackTraceElement[] trace, int start) { 254 if (start >= trace.length) return ""; 255 StackTraceElement s = trace[start]; 256 String name = s.getMethodName(); 257 if (name.contains("lambda$")) { 258 // Try to find a friendlier method name 259 String myFile = s.getFileName(); 260 if (myFile != null) { 261 for (int i = start + 1; i < trace.length; i++) { 262 if (myFile.equals(trace[i].getFileName())) { 263 name = trace[i].getMethodName(); 264 break; 265 } 266 } 267 } 268 } 269 return (name + "(l." + s.getLineNumber() + ")"); 270 } 271 272 // Vendor HAL HIDL interface objects. 273 private IWifiChip mIWifiChip; 274 private HashMap<String, IWifiStaIface> mIWifiStaIfaces = new HashMap<>(); 275 private HashMap<String, IWifiApIface> mIWifiApIfaces = new HashMap<>(); 276 private static Context sContext; 277 private final HalDeviceManager mHalDeviceManager; 278 private final WifiGlobals mWifiGlobals; 279 private final HalDeviceManagerStatusListener mHalDeviceManagerStatusCallbacks; 280 private final IWifiStaIfaceEventCallback mIWifiStaIfaceEventCallback; 281 private final ChipEventCallback mIWifiChipEventCallback; 282 private final ChipEventCallbackV12 mIWifiChipEventCallbackV12; 283 private final ChipEventCallbackV14 mIWifiChipEventCallbackV14; 284 285 // Plumbing for event handling. 286 // 287 // Being final fields, they can be accessed without synchronization under 288 // some reasonable assumptions. See 289 // https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5 290 private final Handler mHalEventHandler; 291 WifiVendorHal(Context context, HalDeviceManager halDeviceManager, Handler handler, WifiGlobals wifiGlobals)292 public WifiVendorHal(Context context, HalDeviceManager halDeviceManager, Handler handler, 293 WifiGlobals wifiGlobals) { 294 sContext = context; 295 mHalDeviceManager = halDeviceManager; 296 mHalEventHandler = handler; 297 mWifiGlobals = wifiGlobals; 298 mHalDeviceManagerStatusCallbacks = new HalDeviceManagerStatusListener(); 299 mIWifiStaIfaceEventCallback = new StaIfaceEventCallback(); 300 mIWifiChipEventCallback = new ChipEventCallback(); 301 mIWifiChipEventCallbackV12 = new ChipEventCallbackV12(); 302 mIWifiChipEventCallbackV14 = new ChipEventCallbackV14(); 303 } 304 305 public static final Object sLock = new Object(); 306 handleRemoteException(RemoteException e)307 private void handleRemoteException(RemoteException e) { 308 String methodName = niceMethodName(Thread.currentThread().getStackTrace(), 3); 309 mVerboseLog.err("% RemoteException in HIDL call %").c(methodName).c(e.toString()).flush(); 310 // Recovery on HAL crash will be triggered by death listener. 311 } 312 313 private WifiNative.VendorHalDeathEventHandler mDeathEventHandler; 314 315 /** 316 * Initialize the Hal device manager and register for status callbacks. 317 * 318 * @param handler Handler to notify if the vendor HAL dies. 319 * @return true on success, false otherwise. 320 */ initialize(WifiNative.VendorHalDeathEventHandler handler)321 public boolean initialize(WifiNative.VendorHalDeathEventHandler handler) { 322 synchronized (sLock) { 323 mHalDeviceManager.initialize(); 324 mHalDeviceManager.registerStatusListener( 325 mHalDeviceManagerStatusCallbacks, mHalEventHandler); 326 mDeathEventHandler = handler; 327 return true; 328 } 329 } 330 331 private WifiNative.VendorHalRadioModeChangeEventHandler mRadioModeChangeEventHandler; 332 333 /** 334 * Register to listen for radio mode change events from the HAL. 335 * 336 * @param handler Handler to notify when the vendor HAL detects a radio mode change. 337 */ registerRadioModeChangeHandler( WifiNative.VendorHalRadioModeChangeEventHandler handler)338 public void registerRadioModeChangeHandler( 339 WifiNative.VendorHalRadioModeChangeEventHandler handler) { 340 synchronized (sLock) { 341 mRadioModeChangeEventHandler = handler; 342 } 343 } 344 345 /** 346 * Register to listen for subsystem restart events from the HAL. 347 * 348 * @param listener SubsystemRestartListener listener object. 349 */ registerSubsystemRestartListener( HalDeviceManager.SubsystemRestartListener listener)350 public void registerSubsystemRestartListener( 351 HalDeviceManager.SubsystemRestartListener listener) { 352 mHalDeviceManager.registerSubsystemRestartListener(listener, mHalEventHandler); 353 } 354 355 /** 356 * Returns whether the vendor HAL is supported on this device or not. 357 */ isVendorHalSupported()358 public boolean isVendorHalSupported() { 359 synchronized (sLock) { 360 return mHalDeviceManager.isSupported(); 361 } 362 } 363 364 /** 365 * Returns whether the vendor HAL is ready or not. 366 */ isVendorHalReady()367 public boolean isVendorHalReady() { 368 synchronized (sLock) { 369 return mHalDeviceManager.isReady(); 370 } 371 } 372 373 /** 374 * Bring up the HIDL Vendor HAL and configure for AP (Access Point) mode 375 * 376 * @return true for success 377 */ startVendorHalAp()378 public boolean startVendorHalAp() { 379 synchronized (sLock) { 380 if (!startVendorHal()) { 381 return false; 382 } 383 if (TextUtils.isEmpty(createApIface(null, null, 384 SoftApConfiguration.BAND_2GHZ, false))) { 385 stopVendorHal(); 386 return false; 387 } 388 return true; 389 } 390 } 391 392 /** 393 * Bring up the HIDL Vendor HAL and configure for STA (Station) mode 394 * 395 * @return true for success 396 */ startVendorHalSta()397 public boolean startVendorHalSta() { 398 synchronized (sLock) { 399 if (!startVendorHal()) { 400 return false; 401 } 402 if (TextUtils.isEmpty(createStaIface(null, null))) { 403 stopVendorHal(); 404 return false; 405 } 406 return true; 407 } 408 } 409 410 /** 411 * Bring up the HIDL Vendor HAL. 412 * @return true on success, false otherwise. 413 */ startVendorHal()414 public boolean startVendorHal() { 415 synchronized (sLock) { 416 if (!mHalDeviceManager.start()) { 417 mLog.err("Failed to start vendor HAL").flush(); 418 return false; 419 } 420 mLog.info("Vendor Hal started successfully").flush(); 421 return true; 422 } 423 } 424 425 426 /** Helper method to lookup the corresponding STA iface object using iface name. */ getStaIface(@onNull String ifaceName)427 private IWifiStaIface getStaIface(@NonNull String ifaceName) { 428 synchronized (sLock) { 429 return mIWifiStaIfaces.get(ifaceName); 430 } 431 } 432 433 private class StaInterfaceDestroyedListenerInternal implements InterfaceDestroyedListener { 434 private final InterfaceDestroyedListener mExternalListener; 435 StaInterfaceDestroyedListenerInternal(InterfaceDestroyedListener externalListener)436 StaInterfaceDestroyedListenerInternal(InterfaceDestroyedListener externalListener) { 437 mExternalListener = externalListener; 438 } 439 440 @Override onDestroyed(@onNull String ifaceName)441 public void onDestroyed(@NonNull String ifaceName) { 442 synchronized (sLock) { 443 mIWifiStaIfaces.remove(ifaceName); 444 } 445 if (mExternalListener != null) { 446 mExternalListener.onDestroyed(ifaceName); 447 } 448 } 449 } 450 451 /** 452 * Create a STA iface using {@link HalDeviceManager}. 453 * 454 * @param destroyedListener Listener to be invoked when the interface is destroyed. 455 * @param requestorWs Requestor worksource. 456 * @return iface name on success, null otherwise. 457 */ createStaIface(@ullable InterfaceDestroyedListener destroyedListener, @NonNull WorkSource requestorWs)458 public String createStaIface(@Nullable InterfaceDestroyedListener destroyedListener, 459 @NonNull WorkSource requestorWs) { 460 synchronized (sLock) { 461 IWifiStaIface iface = mHalDeviceManager.createStaIface( 462 new StaInterfaceDestroyedListenerInternal(destroyedListener), null, 463 requestorWs); 464 if (iface == null) { 465 mLog.err("Failed to create STA iface").flush(); 466 return nullResult(); 467 } 468 String ifaceName = mHalDeviceManager.getName((IWifiIface) iface); 469 if (TextUtils.isEmpty(ifaceName)) { 470 mLog.err("Failed to get iface name").flush(); 471 return nullResult(); 472 } 473 if (!registerStaIfaceCallback(iface)) { 474 mLog.err("Failed to register STA iface callback").flush(); 475 return nullResult(); 476 } 477 if (!retrieveWifiChip((IWifiIface) iface)) { 478 mLog.err("Failed to get wifi chip").flush(); 479 return nullResult(); 480 } 481 enableLinkLayerStats(iface); 482 mIWifiStaIfaces.put(ifaceName, iface); 483 return ifaceName; 484 } 485 } 486 487 /** 488 * Replace the requestor worksource info for a STA iface using {@link HalDeviceManager}. 489 * 490 * @param ifaceName Name of the interface being removed. 491 * @param requestorWs Requestor worksource. 492 * @return true on success, false otherwise. 493 */ replaceStaIfaceRequestorWs(@onNull String ifaceName, @NonNull WorkSource requestorWs)494 public boolean replaceStaIfaceRequestorWs(@NonNull String ifaceName, 495 @NonNull WorkSource requestorWs) { 496 synchronized (sLock) { 497 IWifiStaIface iface = getStaIface(ifaceName); 498 if (iface == null) return boolResult(false); 499 500 if (!mHalDeviceManager.replaceRequestorWs(iface, requestorWs)) { 501 mLog.err("Failed to replace requestor worksource for STA iface").flush(); 502 return boolResult(false); 503 } 504 return true; 505 } 506 } 507 508 /** 509 * Remove a STA iface using {@link HalDeviceManager}. 510 * 511 * @param ifaceName Name of the interface being removed. 512 * @return true on success, false otherwise. 513 */ removeStaIface(@onNull String ifaceName)514 public boolean removeStaIface(@NonNull String ifaceName) { 515 synchronized (sLock) { 516 IWifiStaIface iface = getStaIface(ifaceName); 517 if (iface == null) return boolResult(false); 518 if (!mHalDeviceManager.removeIface((IWifiIface) iface)) { 519 mLog.err("Failed to remove STA iface").flush(); 520 return boolResult(false); 521 } 522 mIWifiStaIfaces.remove(ifaceName); 523 return true; 524 } 525 } 526 527 /** Helper method to lookup the corresponding AP iface object using iface name. */ getApIface(@onNull String ifaceName)528 private IWifiApIface getApIface(@NonNull String ifaceName) { 529 synchronized (sLock) { 530 return mIWifiApIfaces.get(ifaceName); 531 } 532 } 533 534 private class ApInterfaceDestroyedListenerInternal implements InterfaceDestroyedListener { 535 private final InterfaceDestroyedListener mExternalListener; 536 ApInterfaceDestroyedListenerInternal(InterfaceDestroyedListener externalListener)537 ApInterfaceDestroyedListenerInternal(InterfaceDestroyedListener externalListener) { 538 mExternalListener = externalListener; 539 } 540 541 @Override onDestroyed(@onNull String ifaceName)542 public void onDestroyed(@NonNull String ifaceName) { 543 synchronized (sLock) { 544 mIWifiApIfaces.remove(ifaceName); 545 } 546 if (mExternalListener != null) { 547 mExternalListener.onDestroyed(ifaceName); 548 } 549 } 550 } 551 getNecessaryCapabilitiesForSoftApMode(@oftApConfiguration.BandType int band)552 private long getNecessaryCapabilitiesForSoftApMode(@SoftApConfiguration.BandType int band) { 553 long caps = HalDeviceManager.CHIP_CAPABILITY_ANY; 554 if ((band & SoftApConfiguration.BAND_60GHZ) != 0) { 555 caps |= android.hardware.wifi.V1_5.IWifiChip.ChipCapabilityMask.WIGIG; 556 } 557 return caps; 558 } 559 560 /** 561 * Create a AP iface using {@link HalDeviceManager}. 562 * 563 * @param destroyedListener Listener to be invoked when the interface is destroyed. 564 * @param requestorWs Requestor worksource. 565 * @param band The requesting band for this AP interface. 566 * @param isBridged Whether or not AP interface is a bridge interface. 567 * @return iface name on success, null otherwise. 568 */ createApIface(@ullable InterfaceDestroyedListener destroyedListener, @NonNull WorkSource requestorWs, @SoftApConfiguration.BandType int band, boolean isBridged)569 public String createApIface(@Nullable InterfaceDestroyedListener destroyedListener, 570 @NonNull WorkSource requestorWs, 571 @SoftApConfiguration.BandType int band, 572 boolean isBridged) { 573 synchronized (sLock) { 574 IWifiApIface iface = mHalDeviceManager.createApIface( 575 getNecessaryCapabilitiesForSoftApMode(band), 576 new ApInterfaceDestroyedListenerInternal(destroyedListener), null, 577 requestorWs, isBridged); 578 if (iface == null) { 579 mLog.err("Failed to create AP iface").flush(); 580 return nullResult(); 581 } 582 String ifaceName = mHalDeviceManager.getName((IWifiIface) iface); 583 if (TextUtils.isEmpty(ifaceName)) { 584 mLog.err("Failed to get iface name").flush(); 585 return nullResult(); 586 } 587 if (!retrieveWifiChip((IWifiIface) iface)) { 588 mLog.err("Failed to get wifi chip").flush(); 589 return nullResult(); 590 } 591 mIWifiApIfaces.put(ifaceName, iface); 592 return ifaceName; 593 } 594 } 595 596 /** 597 * Replace the requestor worksource info for a AP iface using {@link HalDeviceManager}. 598 * 599 * @param ifaceName Name of the interface being removed. 600 * @param requestorWs Requestor worksource. 601 * @return true on success, false otherwise. 602 */ replaceApIfaceRequestorWs(@onNull String ifaceName, @NonNull WorkSource requestorWs)603 public boolean replaceApIfaceRequestorWs(@NonNull String ifaceName, 604 @NonNull WorkSource requestorWs) { 605 synchronized (sLock) { 606 IWifiApIface iface = getApIface(ifaceName); 607 if (iface == null) return boolResult(false); 608 609 if (!mHalDeviceManager.replaceRequestorWs((IWifiIface) iface, requestorWs)) { 610 mLog.err("Failed to replace requestor worksource for AP iface").flush(); 611 return boolResult(false); 612 } 613 return true; 614 } 615 } 616 617 /** 618 * Remove an AP iface using {@link HalDeviceManager}. 619 * 620 * @param ifaceName Name of the interface being removed. 621 * @return true on success, false otherwise. 622 */ removeApIface(@onNull String ifaceName)623 public boolean removeApIface(@NonNull String ifaceName) { 624 synchronized (sLock) { 625 IWifiApIface iface = getApIface(ifaceName); 626 if (iface == null) return boolResult(false); 627 628 if (!mHalDeviceManager.removeIface((IWifiIface) iface)) { 629 mLog.err("Failed to remove AP iface").flush(); 630 return boolResult(false); 631 } 632 mIWifiApIfaces.remove(ifaceName); 633 return true; 634 } 635 } 636 637 /** 638 * Helper function to remove specific instance in bridged AP iface. 639 * 640 * @param ifaceName Name of the iface. 641 * @param apIfaceInstance The identity of the ap instance. 642 * @return true if the operation succeeded, false if there is an error in Hal. 643 */ removeIfaceInstanceFromBridgedApIface(@onNull String ifaceName, @NonNull String apIfaceInstance)644 public boolean removeIfaceInstanceFromBridgedApIface(@NonNull String ifaceName, 645 @NonNull String apIfaceInstance) { 646 try { 647 android.hardware.wifi.V1_5.IWifiChip iWifiChipV15 = getWifiChipForV1_5Mockable(); 648 if (iWifiChipV15 == null) return boolResult(false); 649 return ok(iWifiChipV15.removeIfaceInstanceFromBridgedApIface( 650 ifaceName, apIfaceInstance)); 651 } catch (RemoteException e) { 652 handleRemoteException(e); 653 return false; 654 } 655 } 656 657 @NonNull 658 private ArrayList<android.hardware.wifi.V1_5.IWifiChip.CoexUnsafeChannel> frameworkCoexUnsafeChannelsToHidl( @onNull List<android.net.wifi.CoexUnsafeChannel> frameworkUnsafeChannels)659 frameworkCoexUnsafeChannelsToHidl( 660 @NonNull List<android.net.wifi.CoexUnsafeChannel> frameworkUnsafeChannels) { 661 final ArrayList<android.hardware.wifi.V1_5.IWifiChip.CoexUnsafeChannel> hidlList = 662 new ArrayList<>(); 663 if (!SdkLevel.isAtLeastS()) { 664 return hidlList; 665 } 666 for (android.net.wifi.CoexUnsafeChannel frameworkUnsafeChannel : frameworkUnsafeChannels) { 667 final android.hardware.wifi.V1_5.IWifiChip.CoexUnsafeChannel hidlUnsafeChannel = 668 new android.hardware.wifi.V1_5.IWifiChip.CoexUnsafeChannel(); 669 switch (frameworkUnsafeChannel.getBand()) { 670 case (WifiScanner.WIFI_BAND_24_GHZ): 671 hidlUnsafeChannel.band = WifiBand.BAND_24GHZ; 672 break; 673 case (WifiScanner.WIFI_BAND_5_GHZ): 674 hidlUnsafeChannel.band = WifiBand.BAND_5GHZ; 675 break; 676 case (WifiScanner.WIFI_BAND_6_GHZ): 677 hidlUnsafeChannel.band = WifiBand.BAND_6GHZ; 678 break; 679 case (WifiScanner.WIFI_BAND_60_GHZ): 680 hidlUnsafeChannel.band = WifiBand.BAND_60GHZ; 681 break; 682 default: 683 mLog.err("Tried to set unsafe channel with unknown band: %") 684 .c(frameworkUnsafeChannel.getBand()) 685 .flush(); 686 continue; 687 } 688 hidlUnsafeChannel.channel = frameworkUnsafeChannel.getChannel(); 689 final int powerCapDbm = frameworkUnsafeChannel.getPowerCapDbm(); 690 if (powerCapDbm != POWER_CAP_NONE) { 691 hidlUnsafeChannel.powerCapDbm = powerCapDbm; 692 } else { 693 hidlUnsafeChannel.powerCapDbm = 694 android.hardware.wifi.V1_5.IWifiChip.PowerCapConstant.NO_POWER_CAP; 695 } 696 hidlList.add(hidlUnsafeChannel); 697 } 698 return hidlList; 699 } 700 frameworkCoexRestrictionsToHidl(@ifiManager.CoexRestriction int restrictions)701 private int frameworkCoexRestrictionsToHidl(@WifiManager.CoexRestriction int restrictions) { 702 int hidlRestrictions = 0; 703 if (!SdkLevel.isAtLeastS()) { 704 return hidlRestrictions; 705 } 706 if ((restrictions & WifiManager.COEX_RESTRICTION_WIFI_DIRECT) != 0) { 707 hidlRestrictions |= android.hardware.wifi.V1_5.IWifiChip.CoexRestriction.WIFI_DIRECT; 708 } 709 if ((restrictions & WifiManager.COEX_RESTRICTION_SOFTAP) != 0) { 710 hidlRestrictions |= android.hardware.wifi.V1_5.IWifiChip.CoexRestriction.SOFTAP; 711 } 712 if ((restrictions & WifiManager.COEX_RESTRICTION_WIFI_AWARE) != 0) { 713 hidlRestrictions |= android.hardware.wifi.V1_5.IWifiChip.CoexRestriction.WIFI_AWARE; 714 } 715 return hidlRestrictions; 716 } 717 718 /** 719 * Set the current coex unsafe channels to avoid and their restrictions. 720 * @param unsafeChannels List of {@link android.net.wifi.CoexUnsafeChannel} to avoid. 721 * @param restrictions int containing a bitwise-OR combination of 722 * {@link WifiManager.CoexRestriction}. 723 * @return true if the operation succeeded, false if there is an error in Hal. 724 */ setCoexUnsafeChannels( @onNull List<android.net.wifi.CoexUnsafeChannel> unsafeChannels, int restrictions)725 public boolean setCoexUnsafeChannels( 726 @NonNull List<android.net.wifi.CoexUnsafeChannel> unsafeChannels, int restrictions) { 727 try { 728 android.hardware.wifi.V1_5.IWifiChip iWifiChipV15 = getWifiChipForV1_5Mockable(); 729 if (iWifiChipV15 == null) return boolResult(false); 730 return ok(iWifiChipV15.setCoexUnsafeChannels( 731 frameworkCoexUnsafeChannelsToHidl(unsafeChannels), 732 frameworkCoexRestrictionsToHidl(restrictions))); 733 } catch (RemoteException e) { 734 handleRemoteException(e); 735 return false; 736 } 737 } 738 retrieveWifiChip(IWifiIface iface)739 private boolean retrieveWifiChip(IWifiIface iface) { 740 synchronized (sLock) { 741 boolean registrationNeeded = mIWifiChip == null; 742 mIWifiChip = mHalDeviceManager.getChip(iface); 743 if (mIWifiChip == null) { 744 mLog.err("Failed to get the chip created for the Iface").flush(); 745 return false; 746 } 747 if (!registrationNeeded) { 748 return true; 749 } 750 if (!registerChipCallback()) { 751 mLog.err("Failed to register chip callback").flush(); 752 mIWifiChip = null; 753 return false; 754 } 755 return true; 756 } 757 } 758 759 /** 760 * Registers the sta iface callback. 761 */ registerStaIfaceCallback(IWifiStaIface iface)762 private boolean registerStaIfaceCallback(IWifiStaIface iface) { 763 synchronized (sLock) { 764 if (iface == null) return boolResult(false); 765 if (mIWifiStaIfaceEventCallback == null) return boolResult(false); 766 try { 767 WifiStatus status = 768 iface.registerEventCallback(mIWifiStaIfaceEventCallback); 769 return ok(status); 770 } catch (RemoteException e) { 771 handleRemoteException(e); 772 return false; 773 } 774 } 775 } 776 777 /** 778 * Registers the sta iface callback. 779 */ registerChipCallback()780 private boolean registerChipCallback() { 781 synchronized (sLock) { 782 if (mIWifiChip == null) return boolResult(false); 783 try { 784 WifiStatus status; 785 android.hardware.wifi.V1_4.IWifiChip iWifiChipV14 = getWifiChipForV1_4Mockable(); 786 android.hardware.wifi.V1_2.IWifiChip iWifiChipV12 = getWifiChipForV1_2Mockable(); 787 788 if (iWifiChipV14 != null) { 789 status = iWifiChipV14.registerEventCallback_1_4(mIWifiChipEventCallbackV14); 790 } else if (iWifiChipV12 != null) { 791 status = iWifiChipV12.registerEventCallback_1_2(mIWifiChipEventCallbackV12); 792 } else { 793 status = mIWifiChip.registerEventCallback(mIWifiChipEventCallback); 794 } 795 return ok(status); 796 } catch (RemoteException e) { 797 handleRemoteException(e); 798 return false; 799 } 800 } 801 } 802 803 /** 804 * Stops the HAL 805 */ stopVendorHal()806 public void stopVendorHal() { 807 synchronized (sLock) { 808 mHalDeviceManager.stop(); 809 clearState(); 810 mLog.info("Vendor Hal stopped").flush(); 811 } 812 } 813 814 /** 815 * Clears the state associated with a started Iface 816 * 817 * Caller should hold the lock. 818 */ clearState()819 private void clearState() { 820 mIWifiChip = null; 821 mIWifiStaIfaces.clear(); 822 mIWifiApIfaces.clear(); 823 mDriverDescription = null; 824 mFirmwareDescription = null; 825 } 826 827 /** 828 * Tests whether the HAL is started and atleast one iface is up. 829 */ isHalStarted()830 public boolean isHalStarted() { 831 // For external use only. Methods in this class should test for null directly. 832 synchronized (sLock) { 833 return (!mIWifiStaIfaces.isEmpty() || !mIWifiApIfaces.isEmpty()); 834 } 835 } 836 837 /** 838 * Gets the scan capabilities 839 * 840 * @param ifaceName Name of the interface. 841 * @param capabilities object to be filled in 842 * @return true for success, false for failure 843 */ getBgScanCapabilities( @onNull String ifaceName, WifiNative.ScanCapabilities capabilities)844 public boolean getBgScanCapabilities( 845 @NonNull String ifaceName, WifiNative.ScanCapabilities capabilities) { 846 synchronized (sLock) { 847 IWifiStaIface iface = getStaIface(ifaceName); 848 if (iface == null) return boolResult(false); 849 try { 850 Mutable<Boolean> ans = new Mutable<>(false); 851 WifiNative.ScanCapabilities out = capabilities; 852 iface.getBackgroundScanCapabilities((status, cap) -> { 853 if (!ok(status)) return; 854 mVerboseLog.info("scan capabilities %").c(cap.toString()).flush(); 855 out.max_scan_cache_size = cap.maxCacheSize; 856 out.max_ap_cache_per_scan = cap.maxApCachePerScan; 857 out.max_scan_buckets = cap.maxBuckets; 858 out.max_rssi_sample_size = 0; 859 out.max_scan_reporting_threshold = cap.maxReportingThreshold; 860 ans.value = true; 861 } 862 ); 863 return ans.value; 864 } catch (RemoteException e) { 865 handleRemoteException(e); 866 return false; 867 } 868 } 869 } 870 871 /** 872 * Holds the current background scan state, to implement pause and restart 873 */ 874 @VisibleForTesting 875 class CurrentBackgroundScan { 876 public int cmdId; 877 public StaBackgroundScanParameters param; 878 public WifiNative.ScanEventHandler eventHandler = null; 879 public boolean paused = false; 880 public WifiScanner.ScanData[] latestScanResults = null; 881 CurrentBackgroundScan(int id, WifiNative.ScanSettings settings)882 CurrentBackgroundScan(int id, WifiNative.ScanSettings settings) { 883 cmdId = id; 884 param = new StaBackgroundScanParameters(); 885 param.basePeriodInMs = settings.base_period_ms; 886 param.maxApPerScan = settings.max_ap_per_scan; 887 param.reportThresholdPercent = settings.report_threshold_percent; 888 param.reportThresholdNumScans = settings.report_threshold_num_scans; 889 if (settings.buckets != null) { 890 for (WifiNative.BucketSettings bs : settings.buckets) { 891 param.buckets.add(makeStaBackgroundScanBucketParametersFromBucketSettings(bs)); 892 } 893 } 894 } 895 } 896 897 /** 898 * Makes the Hal flavor of WifiNative.BucketSettings 899 * 900 * @param bs WifiNative.BucketSettings 901 * @return Hal flavor of bs 902 * @throws IllegalArgumentException if band value is not recognized 903 */ 904 private StaBackgroundScanBucketParameters makeStaBackgroundScanBucketParametersFromBucketSettings(WifiNative.BucketSettings bs)905 makeStaBackgroundScanBucketParametersFromBucketSettings(WifiNative.BucketSettings bs) { 906 StaBackgroundScanBucketParameters pa = new StaBackgroundScanBucketParameters(); 907 pa.bucketIdx = bs.bucket; 908 pa.band = makeWifiBandFromFrameworkBand(bs.band); 909 if (bs.channels != null) { 910 for (WifiNative.ChannelSettings cs : bs.channels) { 911 pa.frequencies.add(cs.frequency); 912 } 913 } 914 pa.periodInMs = bs.period_ms; 915 pa.eventReportScheme = makeReportSchemeFromBucketSettingsReportEvents(bs.report_events); 916 pa.exponentialMaxPeriodInMs = bs.max_period_ms; 917 // Although HAL API allows configurable base value for the truncated 918 // exponential back off scan. Native API and above support only 919 // truncated binary exponential back off scan. 920 // Hard code value of base to 2 here. 921 pa.exponentialBase = 2; 922 pa.exponentialStepCount = bs.step_count; 923 return pa; 924 } 925 926 /** 927 * Makes the Hal flavor of WifiScanner's band indication 928 * 929 * Note: This method is only used by background scan which does not 930 * support 6GHz, hence band combinations including 6GHz are considered invalid 931 * 932 * @param frameworkBand one of WifiScanner.WIFI_BAND_* 933 * @return A WifiBand value 934 * @throws IllegalArgumentException if frameworkBand is not recognized 935 */ makeWifiBandFromFrameworkBand(int frameworkBand)936 private int makeWifiBandFromFrameworkBand(int frameworkBand) { 937 switch (frameworkBand) { 938 case WifiScanner.WIFI_BAND_UNSPECIFIED: 939 return WifiBand.BAND_UNSPECIFIED; 940 case WifiScanner.WIFI_BAND_24_GHZ: 941 return WifiBand.BAND_24GHZ; 942 case WifiScanner.WIFI_BAND_5_GHZ: 943 return WifiBand.BAND_5GHZ; 944 case WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY: 945 return WifiBand.BAND_5GHZ_DFS; 946 case WifiScanner.WIFI_BAND_5_GHZ_WITH_DFS: 947 return WifiBand.BAND_5GHZ_WITH_DFS; 948 case WifiScanner.WIFI_BAND_BOTH: 949 return WifiBand.BAND_24GHZ_5GHZ; 950 case WifiScanner.WIFI_BAND_BOTH_WITH_DFS: 951 return WifiBand.BAND_24GHZ_5GHZ_WITH_DFS; 952 case WifiScanner.WIFI_BAND_6_GHZ: 953 return WifiBand.BAND_6GHZ; 954 case WifiScanner.WIFI_BAND_24_5_6_GHZ: 955 return WifiBand.BAND_24GHZ_5GHZ_6GHZ; 956 case WifiScanner.WIFI_BAND_24_5_WITH_DFS_6_GHZ: 957 return WifiBand.BAND_24GHZ_5GHZ_WITH_DFS_6GHZ; 958 case WifiScanner.WIFI_BAND_60_GHZ: 959 return WifiBand.BAND_60GHZ; 960 case WifiScanner.WIFI_BAND_24_5_6_60_GHZ: 961 return WifiBand.BAND_24GHZ_5GHZ_6GHZ_60GHZ; 962 case WifiScanner.WIFI_BAND_24_5_WITH_DFS_6_60_GHZ: 963 return WifiBand.BAND_24GHZ_5GHZ_WITH_DFS_6GHZ_60GHZ; 964 case WifiScanner.WIFI_BAND_24_GHZ_WITH_5GHZ_DFS: 965 default: 966 throw new IllegalArgumentException("bad band " + frameworkBand); 967 } 968 } 969 970 /** 971 * Makes the Hal flavor of WifiScanner's report event mask 972 * 973 * @param reportUnderscoreEvents is logical OR of WifiScanner.REPORT_EVENT_* values 974 * @return Corresponding StaBackgroundScanBucketEventReportSchemeMask value 975 * @throws IllegalArgumentException if a mask bit is not recognized 976 */ makeReportSchemeFromBucketSettingsReportEvents(int reportUnderscoreEvents)977 private int makeReportSchemeFromBucketSettingsReportEvents(int reportUnderscoreEvents) { 978 int ans = 0; 979 BitMask in = new BitMask(reportUnderscoreEvents); 980 if (in.testAndClear(WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)) { 981 ans |= StaBackgroundScanBucketEventReportSchemeMask.EACH_SCAN; 982 } 983 if (in.testAndClear(WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT)) { 984 ans |= StaBackgroundScanBucketEventReportSchemeMask.FULL_RESULTS; 985 } 986 if (in.testAndClear(WifiScanner.REPORT_EVENT_NO_BATCH)) { 987 ans |= StaBackgroundScanBucketEventReportSchemeMask.NO_BATCH; 988 } 989 if (in.value != 0) throw new IllegalArgumentException("bad " + reportUnderscoreEvents); 990 return ans; 991 } 992 993 private int mLastScanCmdId; // For assigning cmdIds to scans 994 995 @VisibleForTesting 996 CurrentBackgroundScan mScan = null; 997 998 /** 999 * Starts a background scan 1000 * 1001 * Any ongoing scan will be stopped first 1002 * 1003 * @param ifaceName Name of the interface. 1004 * @param settings to control the scan 1005 * @param eventHandler to call with the results 1006 * @return true for success 1007 */ startBgScan(@onNull String ifaceName, WifiNative.ScanSettings settings, WifiNative.ScanEventHandler eventHandler)1008 public boolean startBgScan(@NonNull String ifaceName, 1009 WifiNative.ScanSettings settings, 1010 WifiNative.ScanEventHandler eventHandler) { 1011 WifiStatus status; 1012 if (eventHandler == null) return boolResult(false); 1013 synchronized (sLock) { 1014 IWifiStaIface iface = getStaIface(ifaceName); 1015 if (iface == null) return boolResult(false); 1016 try { 1017 if (mScan != null && !mScan.paused) { 1018 ok(iface.stopBackgroundScan(mScan.cmdId)); 1019 mScan = null; 1020 } 1021 mLastScanCmdId = (mLastScanCmdId % 9) + 1; // cycle through non-zero single digits 1022 CurrentBackgroundScan scan = new CurrentBackgroundScan(mLastScanCmdId, settings); 1023 status = iface.startBackgroundScan(scan.cmdId, scan.param); 1024 if (!ok(status)) return false; 1025 scan.eventHandler = eventHandler; 1026 mScan = scan; 1027 return true; 1028 } catch (RemoteException e) { 1029 handleRemoteException(e); 1030 return false; 1031 } 1032 } 1033 } 1034 1035 1036 /** 1037 * Stops any ongoing backgound scan 1038 * 1039 * @param ifaceName Name of the interface. 1040 */ stopBgScan(@onNull String ifaceName)1041 public void stopBgScan(@NonNull String ifaceName) { 1042 WifiStatus status; 1043 synchronized (sLock) { 1044 IWifiStaIface iface = getStaIface(ifaceName); 1045 if (iface == null) return; 1046 try { 1047 if (mScan != null) { 1048 ok(iface.stopBackgroundScan(mScan.cmdId)); 1049 mScan = null; 1050 } 1051 } catch (RemoteException e) { 1052 handleRemoteException(e); 1053 } 1054 } 1055 } 1056 1057 /** 1058 * Pauses an ongoing backgound scan 1059 * 1060 * @param ifaceName Name of the interface. 1061 */ pauseBgScan(@onNull String ifaceName)1062 public void pauseBgScan(@NonNull String ifaceName) { 1063 WifiStatus status; 1064 synchronized (sLock) { 1065 try { 1066 IWifiStaIface iface = getStaIface(ifaceName); 1067 if (iface == null) return; 1068 if (mScan != null && !mScan.paused) { 1069 status = iface.stopBackgroundScan(mScan.cmdId); 1070 if (!ok(status)) return; 1071 mScan.paused = true; 1072 } 1073 } catch (RemoteException e) { 1074 handleRemoteException(e); 1075 } 1076 } 1077 } 1078 1079 /** 1080 * Restarts a paused background scan 1081 * 1082 * @param ifaceName Name of the interface. 1083 */ restartBgScan(@onNull String ifaceName)1084 public void restartBgScan(@NonNull String ifaceName) { 1085 WifiStatus status; 1086 synchronized (sLock) { 1087 IWifiStaIface iface = getStaIface(ifaceName); 1088 if (iface == null) return; 1089 try { 1090 if (mScan != null && mScan.paused) { 1091 status = iface.startBackgroundScan(mScan.cmdId, mScan.param); 1092 if (!ok(status)) return; 1093 mScan.paused = false; 1094 } 1095 } catch (RemoteException e) { 1096 handleRemoteException(e); 1097 } 1098 } 1099 } 1100 1101 /** 1102 * Gets the latest scan results received from the HIDL interface callback. 1103 * TODO(b/35754840): This hop to fetch scan results after callback is unnecessary. Refactor 1104 * WifiScanner to use the scan results from the callback. 1105 * 1106 * @param ifaceName Name of the interface. 1107 */ getBgScanResults(@onNull String ifaceName)1108 public WifiScanner.ScanData[] getBgScanResults(@NonNull String ifaceName) { 1109 synchronized (sLock) { 1110 IWifiStaIface iface = getStaIface(ifaceName); 1111 if (iface == null) return null; 1112 if (mScan == null) return null; 1113 return mScan.latestScanResults; 1114 } 1115 } 1116 1117 /** 1118 * Get the link layer statistics 1119 * 1120 * Note - we always enable link layer stats on a STA interface. 1121 * 1122 * @param ifaceName Name of the interface. 1123 * @return the statistics, or null if unable to do so 1124 */ getWifiLinkLayerStats(@onNull String ifaceName)1125 public WifiLinkLayerStats getWifiLinkLayerStats(@NonNull String ifaceName) { 1126 if (getWifiStaIfaceForV1_5Mockable(ifaceName) != null) { 1127 return getWifiLinkLayerStats_1_5_Internal(ifaceName); 1128 } else if (getWifiStaIfaceForV1_3Mockable(ifaceName) != null) { 1129 return getWifiLinkLayerStats_1_3_Internal(ifaceName); 1130 } else { 1131 return getWifiLinkLayerStats_internal(ifaceName); 1132 } 1133 } 1134 getWifiLinkLayerStats_internal(@onNull String ifaceName)1135 private WifiLinkLayerStats getWifiLinkLayerStats_internal(@NonNull String ifaceName) { 1136 class AnswerBox { 1137 public StaLinkLayerStats value = null; 1138 } 1139 AnswerBox answer = new AnswerBox(); 1140 synchronized (sLock) { 1141 try { 1142 IWifiStaIface iface = getStaIface(ifaceName); 1143 if (iface == null) return null; 1144 iface.getLinkLayerStats((status, stats) -> { 1145 if (!ok(status)) return; 1146 answer.value = stats; 1147 }); 1148 } catch (RemoteException e) { 1149 handleRemoteException(e); 1150 return null; 1151 } 1152 } 1153 WifiLinkLayerStats stats = frameworkFromHalLinkLayerStats(answer.value); 1154 return stats; 1155 } 1156 getWifiLinkLayerStats_1_3_Internal(@onNull String ifaceName)1157 private WifiLinkLayerStats getWifiLinkLayerStats_1_3_Internal(@NonNull String ifaceName) { 1158 class AnswerBox { 1159 public android.hardware.wifi.V1_3.StaLinkLayerStats value = null; 1160 } 1161 AnswerBox answer = new AnswerBox(); 1162 synchronized (sLock) { 1163 try { 1164 android.hardware.wifi.V1_3.IWifiStaIface iface = 1165 getWifiStaIfaceForV1_3Mockable(ifaceName); 1166 if (iface == null) return null; 1167 iface.getLinkLayerStats_1_3((status, stats) -> { 1168 if (!ok(status)) return; 1169 answer.value = stats; 1170 }); 1171 } catch (RemoteException e) { 1172 handleRemoteException(e); 1173 return null; 1174 } 1175 } 1176 WifiLinkLayerStats stats = frameworkFromHalLinkLayerStats_1_3(answer.value); 1177 return stats; 1178 } 1179 getWifiLinkLayerStats_1_5_Internal(@onNull String ifaceName)1180 private WifiLinkLayerStats getWifiLinkLayerStats_1_5_Internal(@NonNull String ifaceName) { 1181 class AnswerBox { 1182 public android.hardware.wifi.V1_5.StaLinkLayerStats value = null; 1183 } 1184 AnswerBox answer = new AnswerBox(); 1185 synchronized (sLock) { 1186 try { 1187 android.hardware.wifi.V1_5.IWifiStaIface iface = 1188 getWifiStaIfaceForV1_5Mockable(ifaceName); 1189 if (iface == null) return null; 1190 iface.getLinkLayerStats_1_5((status, stats) -> { 1191 if (!ok(status)) return; 1192 answer.value = stats; 1193 }); 1194 } catch (RemoteException e) { 1195 handleRemoteException(e); 1196 return null; 1197 } 1198 } 1199 WifiLinkLayerStats stats = frameworkFromHalLinkLayerStats_1_5(answer.value); 1200 return stats; 1201 } 1202 1203 1204 /** 1205 * Makes the framework version of link layer stats from the hal version. 1206 */ 1207 @VisibleForTesting frameworkFromHalLinkLayerStats(StaLinkLayerStats stats)1208 static WifiLinkLayerStats frameworkFromHalLinkLayerStats(StaLinkLayerStats stats) { 1209 if (stats == null) return null; 1210 WifiLinkLayerStats out = new WifiLinkLayerStats(); 1211 setIfaceStats(out, stats.iface); 1212 setRadioStats(out, stats.radios); 1213 setTimeStamp(out, stats.timeStampInMs); 1214 out.version = WifiLinkLayerStats.V1_0; 1215 return out; 1216 } 1217 1218 /** 1219 * Makes the framework version of link layer stats from the hal version. 1220 */ 1221 @VisibleForTesting frameworkFromHalLinkLayerStats_1_3( android.hardware.wifi.V1_3.StaLinkLayerStats stats)1222 static WifiLinkLayerStats frameworkFromHalLinkLayerStats_1_3( 1223 android.hardware.wifi.V1_3.StaLinkLayerStats stats) { 1224 if (stats == null) return null; 1225 WifiLinkLayerStats out = new WifiLinkLayerStats(); 1226 setIfaceStats(out, stats.iface); 1227 setRadioStats_1_3(out, stats.radios); 1228 setTimeStamp(out, stats.timeStampInMs); 1229 out.version = WifiLinkLayerStats.V1_3; 1230 return out; 1231 } 1232 1233 /** 1234 * Makes the framework version of link layer stats from the hal version. 1235 */ 1236 @VisibleForTesting frameworkFromHalLinkLayerStats_1_5( android.hardware.wifi.V1_5.StaLinkLayerStats stats)1237 static WifiLinkLayerStats frameworkFromHalLinkLayerStats_1_5( 1238 android.hardware.wifi.V1_5.StaLinkLayerStats stats) { 1239 if (stats == null) return null; 1240 WifiLinkLayerStats out = new WifiLinkLayerStats(); 1241 setIfaceStats_1_5(out, stats.iface); 1242 setRadioStats_1_5(out, stats.radios); 1243 setTimeStamp(out, stats.timeStampInMs); 1244 out.version = WifiLinkLayerStats.V1_5; 1245 return out; 1246 } 1247 setIfaceStats(WifiLinkLayerStats stats, StaLinkLayerIfaceStats iface)1248 private static void setIfaceStats(WifiLinkLayerStats stats, StaLinkLayerIfaceStats iface) { 1249 if (iface == null) return; 1250 stats.beacon_rx = iface.beaconRx; 1251 stats.rssi_mgmt = iface.avgRssiMgmt; 1252 // Statistics are broken out by Wireless Multimedia Extensions categories 1253 // WME Best Effort Access Category 1254 stats.rxmpdu_be = iface.wmeBePktStats.rxMpdu; 1255 stats.txmpdu_be = iface.wmeBePktStats.txMpdu; 1256 stats.lostmpdu_be = iface.wmeBePktStats.lostMpdu; 1257 stats.retries_be = iface.wmeBePktStats.retries; 1258 // WME Background Access Category 1259 stats.rxmpdu_bk = iface.wmeBkPktStats.rxMpdu; 1260 stats.txmpdu_bk = iface.wmeBkPktStats.txMpdu; 1261 stats.lostmpdu_bk = iface.wmeBkPktStats.lostMpdu; 1262 stats.retries_bk = iface.wmeBkPktStats.retries; 1263 // WME Video Access Category 1264 stats.rxmpdu_vi = iface.wmeViPktStats.rxMpdu; 1265 stats.txmpdu_vi = iface.wmeViPktStats.txMpdu; 1266 stats.lostmpdu_vi = iface.wmeViPktStats.lostMpdu; 1267 stats.retries_vi = iface.wmeViPktStats.retries; 1268 // WME Voice Access Category 1269 stats.rxmpdu_vo = iface.wmeVoPktStats.rxMpdu; 1270 stats.txmpdu_vo = iface.wmeVoPktStats.txMpdu; 1271 stats.lostmpdu_vo = iface.wmeVoPktStats.lostMpdu; 1272 stats.retries_vo = iface.wmeVoPktStats.retries; 1273 } 1274 setIfaceStats_1_5(WifiLinkLayerStats stats, android.hardware.wifi.V1_5.StaLinkLayerIfaceStats iface)1275 private static void setIfaceStats_1_5(WifiLinkLayerStats stats, 1276 android.hardware.wifi.V1_5.StaLinkLayerIfaceStats iface) { 1277 if (iface == null) return; 1278 setIfaceStats(stats, iface.V1_0); 1279 stats.timeSliceDutyCycleInPercent = iface.timeSliceDutyCycleInPercent; 1280 // WME Best Effort Access Category 1281 stats.contentionTimeMinBeInUsec = iface.wmeBeContentionTimeStats.contentionTimeMinInUsec; 1282 stats.contentionTimeMaxBeInUsec = iface.wmeBeContentionTimeStats.contentionTimeMaxInUsec; 1283 stats.contentionTimeAvgBeInUsec = iface.wmeBeContentionTimeStats.contentionTimeAvgInUsec; 1284 stats.contentionNumSamplesBe = iface.wmeBeContentionTimeStats.contentionNumSamples; 1285 // WME Background Access Category 1286 stats.contentionTimeMinBkInUsec = iface.wmeBkContentionTimeStats.contentionTimeMinInUsec; 1287 stats.contentionTimeMaxBkInUsec = iface.wmeBkContentionTimeStats.contentionTimeMaxInUsec; 1288 stats.contentionTimeAvgBkInUsec = iface.wmeBkContentionTimeStats.contentionTimeAvgInUsec; 1289 stats.contentionNumSamplesBk = iface.wmeBkContentionTimeStats.contentionNumSamples; 1290 // WME Video Access Category 1291 stats.contentionTimeMinViInUsec = iface.wmeViContentionTimeStats.contentionTimeMinInUsec; 1292 stats.contentionTimeMaxViInUsec = iface.wmeViContentionTimeStats.contentionTimeMaxInUsec; 1293 stats.contentionTimeAvgViInUsec = iface.wmeViContentionTimeStats.contentionTimeAvgInUsec; 1294 stats.contentionNumSamplesVi = iface.wmeViContentionTimeStats.contentionNumSamples; 1295 // WME Voice Access Category 1296 stats.contentionTimeMinVoInUsec = iface.wmeVoContentionTimeStats.contentionTimeMinInUsec; 1297 stats.contentionTimeMaxVoInUsec = iface.wmeVoContentionTimeStats.contentionTimeMaxInUsec; 1298 stats.contentionTimeAvgVoInUsec = iface.wmeVoContentionTimeStats.contentionTimeAvgInUsec; 1299 stats.contentionNumSamplesVo = iface.wmeVoContentionTimeStats.contentionNumSamples; 1300 // Peer information statistics 1301 stats.peerInfo = new PeerInfo[iface.peers.size()]; 1302 for (int i = 0; i < stats.peerInfo.length; i++) { 1303 PeerInfo peer = new PeerInfo(); 1304 StaPeerInfo staPeerInfo = iface.peers.get(i); 1305 peer.staCount = staPeerInfo.staCount; 1306 peer.chanUtil = staPeerInfo.chanUtil; 1307 RateStat[] rateStats = new RateStat[staPeerInfo.rateStats.size()]; 1308 for (int j = 0; j < staPeerInfo.rateStats.size(); j++) { 1309 rateStats[j] = new RateStat(); 1310 StaRateStat staRateStat = staPeerInfo.rateStats.get(j); 1311 rateStats[j].preamble = staRateStat.rateInfo.preamble; 1312 rateStats[j].nss = staRateStat.rateInfo.nss; 1313 rateStats[j].bw = staRateStat.rateInfo.bw; 1314 rateStats[j].rateMcsIdx = staRateStat.rateInfo.rateMcsIdx; 1315 rateStats[j].bitRateInKbps = staRateStat.rateInfo.bitRateInKbps; 1316 rateStats[j].txMpdu = staRateStat.txMpdu; 1317 rateStats[j].rxMpdu = staRateStat.rxMpdu; 1318 rateStats[j].mpduLost = staRateStat.mpduLost; 1319 rateStats[j].retries = staRateStat.retries; 1320 } 1321 peer.rateStats = rateStats; 1322 stats.peerInfo[i] = peer; 1323 } 1324 } 1325 setRadioStats(WifiLinkLayerStats stats, List<StaLinkLayerRadioStats> radios)1326 private static void setRadioStats(WifiLinkLayerStats stats, 1327 List<StaLinkLayerRadioStats> radios) { 1328 if (radios == null) return; 1329 // Do not coalesce this info for multi radio devices with older HALs. 1330 if (radios.size() > 0) { 1331 StaLinkLayerRadioStats radioStats = radios.get(0); 1332 stats.on_time = radioStats.onTimeInMs; 1333 stats.tx_time = radioStats.txTimeInMs; 1334 stats.tx_time_per_level = new int[radioStats.txTimeInMsPerLevel.size()]; 1335 for (int i = 0; i < stats.tx_time_per_level.length; i++) { 1336 stats.tx_time_per_level[i] = radioStats.txTimeInMsPerLevel.get(i); 1337 } 1338 stats.rx_time = radioStats.rxTimeInMs; 1339 stats.on_time_scan = radioStats.onTimeInMsForScan; 1340 stats.numRadios = 1; 1341 } 1342 } 1343 1344 /** 1345 * Set individual radio stats from the hal radio stats 1346 */ setFrameworkPerRadioStatsFromHidl(int radioId, RadioStat radio, android.hardware.wifi.V1_3.StaLinkLayerRadioStats hidlRadioStats)1347 private static void setFrameworkPerRadioStatsFromHidl(int radioId, RadioStat radio, 1348 android.hardware.wifi.V1_3.StaLinkLayerRadioStats hidlRadioStats) { 1349 radio.radio_id = radioId; 1350 radio.on_time = hidlRadioStats.V1_0.onTimeInMs; 1351 radio.tx_time = hidlRadioStats.V1_0.txTimeInMs; 1352 radio.rx_time = hidlRadioStats.V1_0.rxTimeInMs; 1353 radio.on_time_scan = hidlRadioStats.V1_0.onTimeInMsForScan; 1354 radio.on_time_nan_scan = hidlRadioStats.onTimeInMsForNanScan; 1355 radio.on_time_background_scan = hidlRadioStats.onTimeInMsForBgScan; 1356 radio.on_time_roam_scan = hidlRadioStats.onTimeInMsForRoamScan; 1357 radio.on_time_pno_scan = hidlRadioStats.onTimeInMsForPnoScan; 1358 radio.on_time_hs20_scan = hidlRadioStats.onTimeInMsForHs20Scan; 1359 /* Copy list of channel stats */ 1360 for (android.hardware.wifi.V1_3.WifiChannelStats channelStats 1361 : hidlRadioStats.channelStats) { 1362 ChannelStats channelStatsEntry = new ChannelStats(); 1363 channelStatsEntry.frequency = channelStats.channel.centerFreq; 1364 channelStatsEntry.radioOnTimeMs = channelStats.onTimeInMs; 1365 channelStatsEntry.ccaBusyTimeMs = channelStats.ccaBusyTimeInMs; 1366 radio.channelStatsMap.put(channelStats.channel.centerFreq, channelStatsEntry); 1367 } 1368 } 1369 1370 /** 1371 * If config_wifiLinkLayerAllRadiosStatsAggregationEnabled is set to true, aggregate 1372 * the radio stats from all the radios else process the stats from Radio 0 only. 1373 */ aggregateFrameworkRadioStatsFromHidl(int radioIndex, WifiLinkLayerStats stats, android.hardware.wifi.V1_3.StaLinkLayerRadioStats hidlRadioStats)1374 private static void aggregateFrameworkRadioStatsFromHidl(int radioIndex, 1375 WifiLinkLayerStats stats, 1376 android.hardware.wifi.V1_3.StaLinkLayerRadioStats hidlRadioStats) { 1377 if (!sContext.getResources() 1378 .getBoolean(R.bool.config_wifiLinkLayerAllRadiosStatsAggregationEnabled) 1379 && radioIndex > 0) { 1380 return; 1381 } 1382 // Aggregate the radio stats from all the radios 1383 stats.on_time += hidlRadioStats.V1_0.onTimeInMs; 1384 stats.tx_time += hidlRadioStats.V1_0.txTimeInMs; 1385 // Aggregate tx_time_per_level based on the assumption that the length of 1386 // txTimeInMsPerLevel is the same across all radios. So txTimeInMsPerLevel on other 1387 // radios at array indices greater than the length of first radio will be dropped. 1388 if (stats.tx_time_per_level == null) { 1389 stats.tx_time_per_level = new int[hidlRadioStats.V1_0.txTimeInMsPerLevel.size()]; 1390 } 1391 for (int i = 0; i < hidlRadioStats.V1_0.txTimeInMsPerLevel.size() 1392 && i < stats.tx_time_per_level.length; i++) { 1393 stats.tx_time_per_level[i] += hidlRadioStats.V1_0.txTimeInMsPerLevel.get(i); 1394 } 1395 stats.rx_time += hidlRadioStats.V1_0.rxTimeInMs; 1396 stats.on_time_scan += hidlRadioStats.V1_0.onTimeInMsForScan; 1397 stats.on_time_nan_scan += hidlRadioStats.onTimeInMsForNanScan; 1398 stats.on_time_background_scan += hidlRadioStats.onTimeInMsForBgScan; 1399 stats.on_time_roam_scan += hidlRadioStats.onTimeInMsForRoamScan; 1400 stats.on_time_pno_scan += hidlRadioStats.onTimeInMsForPnoScan; 1401 stats.on_time_hs20_scan += hidlRadioStats.onTimeInMsForHs20Scan; 1402 /* Copy list of channel stats */ 1403 for (android.hardware.wifi.V1_3.WifiChannelStats channelStats 1404 : hidlRadioStats.channelStats) { 1405 ChannelStats channelStatsEntry = 1406 stats.channelStatsMap.get(channelStats.channel.centerFreq); 1407 if (channelStatsEntry == null) { 1408 channelStatsEntry = new ChannelStats(); 1409 channelStatsEntry.frequency = channelStats.channel.centerFreq; 1410 stats.channelStatsMap.put(channelStats.channel.centerFreq, channelStatsEntry); 1411 } 1412 channelStatsEntry.radioOnTimeMs += channelStats.onTimeInMs; 1413 channelStatsEntry.ccaBusyTimeMs += channelStats.ccaBusyTimeInMs; 1414 } 1415 stats.numRadios++; 1416 } 1417 setRadioStats_1_3(WifiLinkLayerStats stats, List<android.hardware.wifi.V1_3.StaLinkLayerRadioStats> radios)1418 private static void setRadioStats_1_3(WifiLinkLayerStats stats, 1419 List<android.hardware.wifi.V1_3.StaLinkLayerRadioStats> radios) { 1420 if (radios == null) return; 1421 int radioIndex = 0; 1422 for (android.hardware.wifi.V1_3.StaLinkLayerRadioStats radioStats : radios) { 1423 aggregateFrameworkRadioStatsFromHidl(radioIndex, stats, radioStats); 1424 radioIndex++; 1425 } 1426 } 1427 setRadioStats_1_5(WifiLinkLayerStats stats, List<android.hardware.wifi.V1_5.StaLinkLayerRadioStats> radios)1428 private static void setRadioStats_1_5(WifiLinkLayerStats stats, 1429 List<android.hardware.wifi.V1_5.StaLinkLayerRadioStats> radios) { 1430 if (radios == null) return; 1431 int radioIndex = 0; 1432 stats.radioStats = new RadioStat[radios.size()]; 1433 for (android.hardware.wifi.V1_5.StaLinkLayerRadioStats radioStats : radios) { 1434 RadioStat radio = new RadioStat(); 1435 setFrameworkPerRadioStatsFromHidl(radioStats.radioId, radio, radioStats.V1_3); 1436 stats.radioStats[radioIndex] = radio; 1437 aggregateFrameworkRadioStatsFromHidl(radioIndex, stats, radioStats.V1_3); 1438 radioIndex++; 1439 } 1440 } 1441 setTimeStamp(WifiLinkLayerStats stats, long timeStampInMs)1442 private static void setTimeStamp(WifiLinkLayerStats stats, long timeStampInMs) { 1443 stats.timeStampInMs = timeStampInMs; 1444 } 1445 1446 @VisibleForTesting 1447 boolean mLinkLayerStatsDebug = false; // Passed to Hal 1448 1449 /** 1450 * Enables the linkLayerStats in the Hal. 1451 * 1452 * This is called unconditionally whenever we create a STA interface. 1453 * 1454 * @param iface Iface object. 1455 */ enableLinkLayerStats(IWifiStaIface iface)1456 private void enableLinkLayerStats(IWifiStaIface iface) { 1457 synchronized (sLock) { 1458 try { 1459 WifiStatus status; 1460 status = iface.enableLinkLayerStatsCollection(mLinkLayerStatsDebug); 1461 if (!ok(status)) { 1462 mLog.err("unable to enable link layer stats collection").flush(); 1463 } 1464 } catch (RemoteException e) { 1465 handleRemoteException(e); 1466 } 1467 } 1468 } 1469 1470 /** 1471 * Translation table used by getSupportedFeatureSet for translating IWifiChip caps for V1.1 1472 */ 1473 private static final long[][] sChipFeatureCapabilityTranslation = { 1474 {WifiManager.WIFI_FEATURE_TX_POWER_LIMIT, 1475 android.hardware.wifi.V1_1.IWifiChip.ChipCapabilityMask.SET_TX_POWER_LIMIT 1476 }, 1477 {WifiManager.WIFI_FEATURE_D2D_RTT, 1478 android.hardware.wifi.V1_1.IWifiChip.ChipCapabilityMask.D2D_RTT 1479 }, 1480 {WifiManager.WIFI_FEATURE_D2AP_RTT, 1481 android.hardware.wifi.V1_1.IWifiChip.ChipCapabilityMask.D2AP_RTT 1482 } 1483 }; 1484 1485 /** 1486 * Translation table used by getSupportedFeatureSet for translating IWifiChip caps for 1487 * additional capabilities introduced in V1.5 1488 */ 1489 private static final long[][] sChipFeatureCapabilityTranslation15 = { 1490 {WifiManager.WIFI_FEATURE_INFRA_60G, 1491 android.hardware.wifi.V1_5.IWifiChip.ChipCapabilityMask.WIGIG 1492 } 1493 }; 1494 1495 /** 1496 * Translation table used by getSupportedFeatureSet for translating IWifiChip caps for 1497 * additional capabilities introduced in V1.3 1498 */ 1499 private static final long[][] sChipFeatureCapabilityTranslation13 = { 1500 {WifiManager.WIFI_FEATURE_LOW_LATENCY, 1501 android.hardware.wifi.V1_3.IWifiChip.ChipCapabilityMask.SET_LATENCY_MODE 1502 }, 1503 {WifiManager.WIFI_FEATURE_P2P_RAND_MAC, 1504 android.hardware.wifi.V1_3.IWifiChip.ChipCapabilityMask.P2P_RAND_MAC 1505 } 1506 1507 }; 1508 1509 /** 1510 * Feature bit mask translation for Chip V1.1 1511 * 1512 * @param capabilities bitmask defined IWifiChip.ChipCapabilityMask 1513 * @return bitmask defined by WifiManager.WIFI_FEATURE_* 1514 */ 1515 @VisibleForTesting wifiFeatureMaskFromChipCapabilities(int capabilities)1516 int wifiFeatureMaskFromChipCapabilities(int capabilities) { 1517 int features = 0; 1518 for (int i = 0; i < sChipFeatureCapabilityTranslation.length; i++) { 1519 if ((capabilities & sChipFeatureCapabilityTranslation[i][1]) != 0) { 1520 features |= sChipFeatureCapabilityTranslation[i][0]; 1521 } 1522 } 1523 return features; 1524 } 1525 1526 /** 1527 * Feature bit mask translation for Chip V1.5 1528 * 1529 * @param capabilities bitmask defined IWifiChip.ChipCapabilityMask 1530 * @return bitmask defined by WifiManager.WIFI_FEATURE_* 1531 */ 1532 @VisibleForTesting wifiFeatureMaskFromChipCapabilities_1_5(int capabilities)1533 long wifiFeatureMaskFromChipCapabilities_1_5(int capabilities) { 1534 // First collect features from previous versions 1535 long features = wifiFeatureMaskFromChipCapabilities_1_3(capabilities); 1536 1537 // Next collect features for V1_5 version 1538 for (int i = 0; i < sChipFeatureCapabilityTranslation15.length; i++) { 1539 if ((capabilities & sChipFeatureCapabilityTranslation15[i][1]) != 0) { 1540 features |= sChipFeatureCapabilityTranslation15[i][0]; 1541 } 1542 } 1543 return features; 1544 } 1545 1546 /** 1547 * Feature bit mask translation for Chip V1.3 1548 * 1549 * @param capabilities bitmask defined IWifiChip.ChipCapabilityMask 1550 * @return bitmask defined by WifiManager.WIFI_FEATURE_* 1551 */ 1552 @VisibleForTesting wifiFeatureMaskFromChipCapabilities_1_3(int capabilities)1553 long wifiFeatureMaskFromChipCapabilities_1_3(int capabilities) { 1554 // First collect features from previous versions 1555 long features = wifiFeatureMaskFromChipCapabilities(capabilities); 1556 1557 // Next collect features for V1_3 version 1558 for (int i = 0; i < sChipFeatureCapabilityTranslation13.length; i++) { 1559 if ((capabilities & sChipFeatureCapabilityTranslation13[i][1]) != 0) { 1560 features |= sChipFeatureCapabilityTranslation13[i][0]; 1561 } 1562 } 1563 return features; 1564 } 1565 1566 /** 1567 * Translation table used by getSupportedFeatureSet for translating IWifiStaIface caps 1568 */ 1569 private static final long[][] sStaFeatureCapabilityTranslation = { 1570 {WifiManager.WIFI_FEATURE_PASSPOINT, 1571 IWifiStaIface.StaIfaceCapabilityMask.HOTSPOT 1572 }, 1573 {WifiManager.WIFI_FEATURE_SCANNER, 1574 IWifiStaIface.StaIfaceCapabilityMask.BACKGROUND_SCAN, 1575 }, 1576 {WifiManager.WIFI_FEATURE_PNO, 1577 IWifiStaIface.StaIfaceCapabilityMask.PNO 1578 }, 1579 {WifiManager.WIFI_FEATURE_TDLS, 1580 IWifiStaIface.StaIfaceCapabilityMask.TDLS 1581 }, 1582 {WifiManager.WIFI_FEATURE_TDLS_OFFCHANNEL, 1583 IWifiStaIface.StaIfaceCapabilityMask.TDLS_OFFCHANNEL 1584 }, 1585 {WifiManager.WIFI_FEATURE_LINK_LAYER_STATS, 1586 IWifiStaIface.StaIfaceCapabilityMask.LINK_LAYER_STATS 1587 }, 1588 {WifiManager.WIFI_FEATURE_RSSI_MONITOR, 1589 IWifiStaIface.StaIfaceCapabilityMask.RSSI_MONITOR 1590 }, 1591 {WifiManager.WIFI_FEATURE_MKEEP_ALIVE, 1592 IWifiStaIface.StaIfaceCapabilityMask.KEEP_ALIVE 1593 }, 1594 {WifiManager.WIFI_FEATURE_CONFIG_NDO, 1595 IWifiStaIface.StaIfaceCapabilityMask.ND_OFFLOAD 1596 }, 1597 {WifiManager.WIFI_FEATURE_CONTROL_ROAMING, 1598 IWifiStaIface.StaIfaceCapabilityMask.CONTROL_ROAMING 1599 }, 1600 {WifiManager.WIFI_FEATURE_IE_WHITELIST, 1601 IWifiStaIface.StaIfaceCapabilityMask.PROBE_IE_WHITELIST 1602 }, 1603 {WifiManager.WIFI_FEATURE_SCAN_RAND, 1604 IWifiStaIface.StaIfaceCapabilityMask.SCAN_RAND 1605 } 1606 }; 1607 1608 /** 1609 * Feature bit mask translation for STAs 1610 * 1611 * @param capabilities bitmask defined IWifiStaIface.StaIfaceCapabilityMask 1612 * @return bitmask defined by WifiManager.WIFI_FEATURE_* 1613 */ 1614 @VisibleForTesting wifiFeatureMaskFromStaCapabilities(int capabilities)1615 long wifiFeatureMaskFromStaCapabilities(int capabilities) { 1616 long features = 0; 1617 for (int i = 0; i < sStaFeatureCapabilityTranslation.length; i++) { 1618 if ((capabilities & sStaFeatureCapabilityTranslation[i][1]) != 0) { 1619 features |= sStaFeatureCapabilityTranslation[i][0]; 1620 } 1621 } 1622 return features; 1623 } 1624 1625 /** 1626 * Translation table used by getSupportedFeatureSetFromPackageManager 1627 * for translating System caps 1628 */ 1629 private static final Pair[] sSystemFeatureCapabilityTranslation = new Pair[] { 1630 Pair.create(WifiManager.WIFI_FEATURE_INFRA, PackageManager.FEATURE_WIFI), 1631 Pair.create(WifiManager.WIFI_FEATURE_P2P, PackageManager.FEATURE_WIFI_DIRECT), 1632 Pair.create(WifiManager.WIFI_FEATURE_AWARE, PackageManager.FEATURE_WIFI_AWARE), 1633 }; 1634 1635 /** 1636 * If VendorHal is not supported, reading PackageManager 1637 * system features to return basic capabilities. 1638 * 1639 * @return bitmask defined by WifiManager.WIFI_FEATURE_* 1640 */ getSupportedFeatureSetFromPackageManager()1641 private long getSupportedFeatureSetFromPackageManager() { 1642 long featureSet = 0; 1643 final PackageManager pm = sContext.getPackageManager(); 1644 for (Pair pair: sSystemFeatureCapabilityTranslation) { 1645 if (pm.hasSystemFeature((String) pair.second)) { 1646 featureSet |= (long) pair.first; 1647 } 1648 } 1649 enter("System feature set: %").c(featureSet).flush(); 1650 return featureSet; 1651 } 1652 1653 /** 1654 * Get the supported features 1655 * 1656 * The result may differ depending on the mode (STA or AP) 1657 * 1658 * @param ifaceName Name of the interface. 1659 * @return bitmask defined by WifiManager.WIFI_FEATURE_* 1660 */ getSupportedFeatureSet(@onNull String ifaceName)1661 public long getSupportedFeatureSet(@NonNull String ifaceName) { 1662 long featureSet = 0; 1663 if (!mHalDeviceManager.isStarted() || !mHalDeviceManager.isSupported()) { 1664 return getSupportedFeatureSetFromPackageManager(); 1665 } 1666 try { 1667 final Mutable<Long> feat = new Mutable<>(0L); 1668 synchronized (sLock) { 1669 android.hardware.wifi.V1_3.IWifiChip iWifiChipV13 = getWifiChipForV1_3Mockable(); 1670 android.hardware.wifi.V1_5.IWifiChip iWifiChipV15 = getWifiChipForV1_5Mockable(); 1671 if (iWifiChipV15 != null) { 1672 iWifiChipV15.getCapabilities_1_5((status, capabilities) -> { 1673 if (!ok(status)) return; 1674 feat.value = wifiFeatureMaskFromChipCapabilities_1_5(capabilities); 1675 }); 1676 } else if (iWifiChipV13 != null) { 1677 iWifiChipV13.getCapabilities_1_3((status, capabilities) -> { 1678 if (!ok(status)) return; 1679 feat.value = wifiFeatureMaskFromChipCapabilities_1_3(capabilities); 1680 }); 1681 } else if (mIWifiChip != null) { 1682 mIWifiChip.getCapabilities((status, capabilities) -> { 1683 if (!ok(status)) return; 1684 feat.value = (long) wifiFeatureMaskFromChipCapabilities(capabilities); 1685 }); 1686 } 1687 1688 IWifiStaIface iface = getStaIface(ifaceName); 1689 if (iface != null) { 1690 iface.getCapabilities((status, capabilities) -> { 1691 if (!ok(status)) return; 1692 feat.value |= wifiFeatureMaskFromStaCapabilities(capabilities); 1693 }); 1694 } 1695 } 1696 featureSet = feat.value; 1697 } catch (RemoteException e) { 1698 handleRemoteException(e); 1699 return 0; 1700 } 1701 1702 if (mWifiGlobals.isWpa3SaeH2eSupported()) { 1703 featureSet |= WifiManager.WIFI_FEATURE_SAE_H2E; 1704 } 1705 1706 Set<Integer> supportedIfaceTypes = mHalDeviceManager.getSupportedIfaceTypes(); 1707 if (supportedIfaceTypes.contains(IfaceType.STA)) { 1708 featureSet |= WifiManager.WIFI_FEATURE_INFRA; 1709 } 1710 if (supportedIfaceTypes.contains(IfaceType.AP)) { 1711 featureSet |= WifiManager.WIFI_FEATURE_MOBILE_HOTSPOT; 1712 } 1713 if (supportedIfaceTypes.contains(IfaceType.P2P)) { 1714 featureSet |= WifiManager.WIFI_FEATURE_P2P; 1715 } 1716 if (supportedIfaceTypes.contains(IfaceType.NAN)) { 1717 featureSet |= WifiManager.WIFI_FEATURE_AWARE; 1718 } 1719 1720 return featureSet; 1721 } 1722 1723 /** 1724 * Set Mac address on the given interface 1725 * 1726 * @param ifaceName Name of the interface 1727 * @param mac MAC address to change into 1728 * @return true for success 1729 */ setStaMacAddress(@onNull String ifaceName, @NonNull MacAddress mac)1730 public boolean setStaMacAddress(@NonNull String ifaceName, @NonNull MacAddress mac) { 1731 byte[] macByteArray = mac.toByteArray(); 1732 synchronized (sLock) { 1733 try { 1734 android.hardware.wifi.V1_2.IWifiStaIface sta12 = 1735 getWifiStaIfaceForV1_2Mockable(ifaceName); 1736 if (sta12 == null) return boolResult(false); 1737 return ok(sta12.setMacAddress(macByteArray)); 1738 } catch (RemoteException e) { 1739 handleRemoteException(e); 1740 return false; 1741 } 1742 } 1743 } 1744 1745 /** 1746 * Reset MAC address to factory MAC address on the given interface 1747 * 1748 * @param ifaceName Name of the interface 1749 * @return true for success 1750 */ resetApMacToFactoryMacAddress(@onNull String ifaceName)1751 public boolean resetApMacToFactoryMacAddress(@NonNull String ifaceName) { 1752 synchronized (sLock) { 1753 try { 1754 android.hardware.wifi.V1_5.IWifiApIface ap15 = 1755 getWifiApIfaceForV1_5Mockable(ifaceName); 1756 if (ap15 == null) { 1757 MacAddress mac = getApFactoryMacAddress(ifaceName); 1758 return mac != null && setApMacAddress(ifaceName, mac); 1759 } 1760 return ok(ap15.resetToFactoryMacAddress()); 1761 } catch (RemoteException e) { 1762 handleRemoteException(e); 1763 return false; 1764 } 1765 } 1766 } 1767 1768 /** 1769 * Set Mac address on the given interface 1770 * 1771 * @param ifaceName Name of the interface 1772 * @param mac MAC address to change into 1773 * @return true for success 1774 */ setApMacAddress(@onNull String ifaceName, @NonNull MacAddress mac)1775 public boolean setApMacAddress(@NonNull String ifaceName, @NonNull MacAddress mac) { 1776 byte[] macByteArray = mac.toByteArray(); 1777 synchronized (sLock) { 1778 try { 1779 android.hardware.wifi.V1_4.IWifiApIface ap14 = 1780 getWifiApIfaceForV1_4Mockable(ifaceName); 1781 if (ap14 == null) return boolResult(false); 1782 return ok(ap14.setMacAddress(macByteArray)); 1783 } catch (RemoteException e) { 1784 handleRemoteException(e); 1785 return false; 1786 } 1787 } 1788 } 1789 1790 /** 1791 * Returns true if Hal version supports setMacAddress, otherwise false. 1792 * 1793 * @param ifaceName Name of the interface 1794 */ isStaSetMacAddressSupported(@onNull String ifaceName)1795 public boolean isStaSetMacAddressSupported(@NonNull String ifaceName) { 1796 synchronized (sLock) { 1797 android.hardware.wifi.V1_2.IWifiStaIface sta12 = 1798 getWifiStaIfaceForV1_2Mockable(ifaceName); 1799 return sta12 != null; 1800 } 1801 } 1802 1803 /** 1804 * Returns true if Hal version supports setMacAddress, otherwise false. 1805 * 1806 * @param ifaceName Name of the interface 1807 */ isApSetMacAddressSupported(@onNull String ifaceName)1808 public boolean isApSetMacAddressSupported(@NonNull String ifaceName) { 1809 synchronized (sLock) { 1810 android.hardware.wifi.V1_4.IWifiApIface ap14 = 1811 getWifiApIfaceForV1_4Mockable(ifaceName); 1812 return ap14 != null; 1813 } 1814 } 1815 1816 /** 1817 * Get factory MAC address of the given interface 1818 * 1819 * @param ifaceName Name of the interface 1820 * @return factory MAC address of the interface or null. 1821 */ getStaFactoryMacAddress(@onNull String ifaceName)1822 public MacAddress getStaFactoryMacAddress(@NonNull String ifaceName) { 1823 class AnswerBox { 1824 public MacAddress mac = null; 1825 } 1826 synchronized (sLock) { 1827 try { 1828 AnswerBox box = new AnswerBox(); 1829 1830 android.hardware.wifi.V1_3.IWifiStaIface sta13 = 1831 getWifiStaIfaceForV1_3Mockable(ifaceName); 1832 if (sta13 == null) return null; 1833 sta13.getFactoryMacAddress((status, macBytes) -> { 1834 if (!ok(status)) return; 1835 box.mac = MacAddress.fromBytes(macBytes); 1836 }); 1837 return box.mac; 1838 } catch (RemoteException e) { 1839 handleRemoteException(e); 1840 return null; 1841 } 1842 } 1843 } 1844 1845 /** 1846 * Get factory MAC address of the given interface 1847 * 1848 * @param ifaceName Name of the interface 1849 * @return factory MAC address of the interface or null. 1850 */ getApFactoryMacAddress(@onNull String ifaceName)1851 public MacAddress getApFactoryMacAddress(@NonNull String ifaceName) { 1852 class AnswerBox { 1853 public MacAddress mac = null; 1854 } 1855 synchronized (sLock) { 1856 try { 1857 AnswerBox box = new AnswerBox(); 1858 android.hardware.wifi.V1_4.IWifiApIface ap14 = 1859 getWifiApIfaceForV1_4Mockable(ifaceName); 1860 if (ap14 == null) return null; 1861 ap14.getFactoryMacAddress((status, macBytes) -> { 1862 if (!ok(status)) return; 1863 box.mac = MacAddress.fromBytes(macBytes); 1864 }); 1865 return box.mac; 1866 } catch (RemoteException e) { 1867 handleRemoteException(e); 1868 return null; 1869 } 1870 } 1871 } 1872 1873 /** 1874 * Get the APF (Android Packet Filter) capabilities of the device 1875 * 1876 * @param ifaceName Name of the interface. 1877 * @return APF capabilities object. 1878 */ getApfCapabilities(@onNull String ifaceName)1879 public ApfCapabilities getApfCapabilities(@NonNull String ifaceName) { 1880 class AnswerBox { 1881 public ApfCapabilities value = sNoApfCapabilities; 1882 } 1883 synchronized (sLock) { 1884 try { 1885 IWifiStaIface iface = getStaIface(ifaceName); 1886 if (iface == null) return sNoApfCapabilities; 1887 AnswerBox box = new AnswerBox(); 1888 iface.getApfPacketFilterCapabilities((status, capabilities) -> { 1889 if (!ok(status)) return; 1890 box.value = new ApfCapabilities( 1891 /* apfVersionSupported */ capabilities.version, 1892 /* maximumApfProgramSize */ capabilities.maxLength, 1893 /* apfPacketFormat */ android.system.OsConstants.ARPHRD_ETHER); 1894 }); 1895 return box.value; 1896 } catch (RemoteException e) { 1897 handleRemoteException(e); 1898 return sNoApfCapabilities; 1899 } 1900 } 1901 } 1902 1903 private static final ApfCapabilities sNoApfCapabilities = new ApfCapabilities(0, 0, 0); 1904 1905 /** 1906 * Installs an APF program on this iface, replacing any existing program. 1907 * 1908 * @param ifaceName Name of the interface. 1909 * @param filter is the android packet filter program 1910 * @return true for success 1911 */ installPacketFilter(@onNull String ifaceName, byte[] filter)1912 public boolean installPacketFilter(@NonNull String ifaceName, byte[] filter) { 1913 int cmdId = 0; // We only aspire to support one program at a time 1914 if (filter == null) return boolResult(false); 1915 // Copy the program before taking the lock. 1916 ArrayList<Byte> program = NativeUtil.byteArrayToArrayList(filter); 1917 enter("filter length %").c(filter.length).flush(); 1918 synchronized (sLock) { 1919 try { 1920 IWifiStaIface iface = getStaIface(ifaceName); 1921 if (iface == null) return boolResult(false); 1922 WifiStatus status = iface.installApfPacketFilter(cmdId, program); 1923 if (!ok(status)) return false; 1924 return true; 1925 } catch (RemoteException e) { 1926 handleRemoteException(e); 1927 return false; 1928 } 1929 } 1930 } 1931 1932 /** 1933 * Reads the APF program and data buffer on this iface. 1934 * 1935 * @param ifaceName Name of the interface 1936 * @return the buffer returned by the driver, or null in case of an error 1937 */ readPacketFilter(@onNull String ifaceName)1938 public byte[] readPacketFilter(@NonNull String ifaceName) { 1939 class AnswerBox { 1940 public byte[] data = null; 1941 } 1942 AnswerBox answer = new AnswerBox(); 1943 enter("").flush(); 1944 // TODO: Must also take the wakelock here to prevent going to sleep with APF disabled. 1945 synchronized (sLock) { 1946 try { 1947 android.hardware.wifi.V1_2.IWifiStaIface ifaceV12 = 1948 getWifiStaIfaceForV1_2Mockable(ifaceName); 1949 if (ifaceV12 == null) return byteArrayResult(null); 1950 ifaceV12.readApfPacketFilterData((status, dataByteArray) -> { 1951 if (!ok(status)) return; 1952 answer.data = NativeUtil.byteArrayFromArrayList(dataByteArray); 1953 }); 1954 return byteArrayResult(answer.data); 1955 } catch (RemoteException e) { 1956 handleRemoteException(e); 1957 return byteArrayResult(null); 1958 } 1959 } 1960 } 1961 1962 /** 1963 * Set country code for this Wifi chip 1964 * 1965 * @param countryCode - two-letter country code (as ISO 3166) 1966 * @return true for success 1967 */ setChipCountryCode(String countryCode)1968 public boolean setChipCountryCode(String countryCode) { 1969 if (countryCode == null) return boolResult(false); 1970 if (countryCode.length() != 2) return boolResult(false); 1971 byte[] code; 1972 try { 1973 code = NativeUtil.stringToByteArray(countryCode); 1974 } catch (IllegalArgumentException e) { 1975 return boolResult(false); 1976 } 1977 synchronized (sLock) { 1978 try { 1979 android.hardware.wifi.V1_5.IWifiChip iWifiChipV15 = getWifiChipForV1_5Mockable(); 1980 if (iWifiChipV15 == null) return boolResult(false); 1981 WifiStatus status = iWifiChipV15.setCountryCode(code); 1982 if (!ok(status)) return false; 1983 return true; 1984 } catch (RemoteException e) { 1985 handleRemoteException(e); 1986 return false; 1987 } 1988 } 1989 } 1990 1991 /** 1992 * Get the names of the bridged AP instances. 1993 * 1994 * @param ifaceName Name of the bridged interface. 1995 * @return A list which contains the names of the bridged AP instances. 1996 */ 1997 @Nullable getBridgedApInstances(@onNull String ifaceName)1998 public List<String> getBridgedApInstances(@NonNull String ifaceName) { 1999 synchronized (sLock) { 2000 try { 2001 Mutable<List<String>> instancesResp = new Mutable<>(); 2002 android.hardware.wifi.V1_5.IWifiApIface ap15 = 2003 getWifiApIfaceForV1_5Mockable(ifaceName); 2004 if (ap15 == null) return null; 2005 ap15.getBridgedInstances((status, instances) -> { 2006 if (!ok(status)) return; 2007 instancesResp.value = new ArrayList<>(instances); 2008 }); 2009 return instancesResp.value; 2010 } catch (RemoteException e) { 2011 handleRemoteException(e); 2012 return null; 2013 } 2014 } 2015 } 2016 2017 /** 2018 * Set country code for this AP iface. 2019 * 2020 * @param ifaceName Name of the interface. 2021 * @param countryCode - two-letter country code (as ISO 3166) 2022 * @return true for success 2023 */ setApCountryCode(@onNull String ifaceName, String countryCode)2024 public boolean setApCountryCode(@NonNull String ifaceName, String countryCode) { 2025 if (countryCode == null) return boolResult(false); 2026 if (countryCode.length() != 2) return boolResult(false); 2027 byte[] code; 2028 try { 2029 code = NativeUtil.stringToByteArray(countryCode); 2030 } catch (IllegalArgumentException e) { 2031 return boolResult(false); 2032 } 2033 synchronized (sLock) { 2034 try { 2035 IWifiApIface iface = getApIface(ifaceName); 2036 if (iface == null) return boolResult(false); 2037 WifiStatus status = iface.setCountryCode(code); 2038 if (!ok(status)) return false; 2039 return true; 2040 } catch (RemoteException e) { 2041 handleRemoteException(e); 2042 return false; 2043 } 2044 } 2045 } 2046 2047 private WifiNative.WifiLoggerEventHandler mLogEventHandler = null; 2048 2049 /** 2050 * Registers the logger callback and enables alerts. 2051 * Ring buffer data collection is only triggered when |startLoggingRingBuffer| is invoked. 2052 */ setLoggingEventHandler(WifiNative.WifiLoggerEventHandler handler)2053 public boolean setLoggingEventHandler(WifiNative.WifiLoggerEventHandler handler) { 2054 if (handler == null) return boolResult(false); 2055 synchronized (sLock) { 2056 if (mIWifiChip == null) return boolResult(false); 2057 if (mLogEventHandler != null) return boolResult(false); 2058 try { 2059 WifiStatus status = mIWifiChip.enableDebugErrorAlerts(true); 2060 if (!ok(status)) return false; 2061 mLogEventHandler = handler; 2062 return true; 2063 } catch (RemoteException e) { 2064 handleRemoteException(e); 2065 return false; 2066 } 2067 } 2068 } 2069 2070 /** 2071 * Stops all logging and resets the logger callback. 2072 * This stops both the alerts and ring buffer data collection. 2073 * Existing log handler is cleared. 2074 */ resetLogHandler()2075 public boolean resetLogHandler() { 2076 synchronized (sLock) { 2077 mLogEventHandler = null; 2078 if (mIWifiChip == null) return boolResult(false); 2079 try { 2080 WifiStatus status = mIWifiChip.enableDebugErrorAlerts(false); 2081 if (!ok(status)) return false; 2082 status = mIWifiChip.stopLoggingToDebugRingBuffer(); 2083 if (!ok(status)) return false; 2084 return true; 2085 } catch (RemoteException e) { 2086 handleRemoteException(e); 2087 return false; 2088 } 2089 } 2090 } 2091 2092 /** 2093 * Control debug data collection 2094 * 2095 * @param verboseLevel 0 to 3, inclusive. 0 stops logging. 2096 * @param flags Ignored. 2097 * @param maxIntervalInSec Maximum interval between reports; ignore if 0. 2098 * @param minDataSizeInBytes Minimum data size in buffer for report; ignore if 0. 2099 * @param ringName Name of the ring for which data collection is to start. 2100 * @return true for success 2101 */ startLoggingRingBuffer(int verboseLevel, int flags, int maxIntervalInSec, int minDataSizeInBytes, String ringName)2102 public boolean startLoggingRingBuffer(int verboseLevel, int flags, int maxIntervalInSec, 2103 int minDataSizeInBytes, String ringName) { 2104 enter("verboseLevel=%, flags=%, maxIntervalInSec=%, minDataSizeInBytes=%, ringName=%") 2105 .c(verboseLevel).c(flags).c(maxIntervalInSec).c(minDataSizeInBytes).c(ringName) 2106 .flush(); 2107 synchronized (sLock) { 2108 if (mIWifiChip == null) return boolResult(false); 2109 try { 2110 // note - flags are not used 2111 WifiStatus status = mIWifiChip.startLoggingToDebugRingBuffer( 2112 ringName, 2113 verboseLevel, 2114 maxIntervalInSec, 2115 minDataSizeInBytes 2116 ); 2117 return ok(status); 2118 } catch (RemoteException e) { 2119 handleRemoteException(e); 2120 return false; 2121 } 2122 } 2123 } 2124 2125 /** 2126 * Pointlessly fail 2127 * 2128 * @return -1 2129 */ getSupportedLoggerFeatureSet()2130 public int getSupportedLoggerFeatureSet() { 2131 return -1; 2132 } 2133 2134 private String mDriverDescription; // Cached value filled by requestChipDebugInfo() 2135 2136 /** 2137 * Vendor-provided wifi driver version string 2138 */ getDriverVersion()2139 public String getDriverVersion() { 2140 synchronized (sLock) { 2141 if (mDriverDescription == null) requestChipDebugInfo(); 2142 return mDriverDescription; 2143 } 2144 } 2145 2146 private String mFirmwareDescription; // Cached value filled by requestChipDebugInfo() 2147 2148 /** 2149 * Vendor-provided wifi firmware version string 2150 */ getFirmwareVersion()2151 public String getFirmwareVersion() { 2152 synchronized (sLock) { 2153 if (mFirmwareDescription == null) requestChipDebugInfo(); 2154 return mFirmwareDescription; 2155 } 2156 } 2157 2158 /** 2159 * Refreshes our idea of the driver and firmware versions 2160 */ requestChipDebugInfo()2161 private void requestChipDebugInfo() { 2162 mDriverDescription = null; 2163 mFirmwareDescription = null; 2164 try { 2165 if (mIWifiChip == null) return; 2166 mIWifiChip.requestChipDebugInfo((status, chipDebugInfo) -> { 2167 if (!ok(status)) return; 2168 mDriverDescription = chipDebugInfo.driverDescription; 2169 mFirmwareDescription = chipDebugInfo.firmwareDescription; 2170 }); 2171 } catch (RemoteException e) { 2172 handleRemoteException(e); 2173 return; 2174 } 2175 mLog.info("Driver: % Firmware: %") 2176 .c(mDriverDescription) 2177 .c(mFirmwareDescription) 2178 .flush(); 2179 } 2180 2181 /** 2182 * Creates RingBufferStatus from the Hal version 2183 */ ringBufferStatus(WifiDebugRingBufferStatus h)2184 private static WifiNative.RingBufferStatus ringBufferStatus(WifiDebugRingBufferStatus h) { 2185 WifiNative.RingBufferStatus ans = new WifiNative.RingBufferStatus(); 2186 ans.name = h.ringName; 2187 ans.flag = frameworkRingBufferFlagsFromHal(h.flags); 2188 ans.ringBufferId = h.ringId; 2189 ans.ringBufferByteSize = h.sizeInBytes; 2190 ans.verboseLevel = h.verboseLevel; 2191 // Remaining fields are unavailable 2192 // writtenBytes; 2193 // readBytes; 2194 // writtenRecords; 2195 return ans; 2196 } 2197 2198 /** 2199 * Translates a hal wifiDebugRingBufferFlag to the WifiNative version 2200 */ frameworkRingBufferFlagsFromHal(int wifiDebugRingBufferFlag)2201 private static int frameworkRingBufferFlagsFromHal(int wifiDebugRingBufferFlag) { 2202 BitMask checkoff = new BitMask(wifiDebugRingBufferFlag); 2203 int flags = 0; 2204 if (checkoff.testAndClear(WifiDebugRingBufferFlags.HAS_BINARY_ENTRIES)) { 2205 flags |= WifiNative.RingBufferStatus.HAS_BINARY_ENTRIES; 2206 } 2207 if (checkoff.testAndClear(WifiDebugRingBufferFlags.HAS_ASCII_ENTRIES)) { 2208 flags |= WifiNative.RingBufferStatus.HAS_ASCII_ENTRIES; 2209 } 2210 if (checkoff.testAndClear(WifiDebugRingBufferFlags.HAS_PER_PACKET_ENTRIES)) { 2211 flags |= WifiNative.RingBufferStatus.HAS_PER_PACKET_ENTRIES; 2212 } 2213 if (checkoff.value != 0) { 2214 throw new IllegalArgumentException("Unknown WifiDebugRingBufferFlag " + checkoff.value); 2215 } 2216 return flags; 2217 } 2218 2219 /** 2220 * Creates array of RingBufferStatus from the Hal version 2221 */ makeRingBufferStatusArray( ArrayList<WifiDebugRingBufferStatus> ringBuffers)2222 private static WifiNative.RingBufferStatus[] makeRingBufferStatusArray( 2223 ArrayList<WifiDebugRingBufferStatus> ringBuffers) { 2224 WifiNative.RingBufferStatus[] ans = new WifiNative.RingBufferStatus[ringBuffers.size()]; 2225 int i = 0; 2226 for (WifiDebugRingBufferStatus b : ringBuffers) { 2227 ans[i++] = ringBufferStatus(b); 2228 } 2229 return ans; 2230 } 2231 2232 /** 2233 * API to get the status of all ring buffers supported by driver 2234 */ getRingBufferStatus()2235 public WifiNative.RingBufferStatus[] getRingBufferStatus() { 2236 class AnswerBox { 2237 public WifiNative.RingBufferStatus[] value = null; 2238 } 2239 AnswerBox ans = new AnswerBox(); 2240 synchronized (sLock) { 2241 if (mIWifiChip == null) return null; 2242 try { 2243 mIWifiChip.getDebugRingBuffersStatus((status, ringBuffers) -> { 2244 if (!ok(status)) return; 2245 ans.value = makeRingBufferStatusArray(ringBuffers); 2246 }); 2247 } catch (RemoteException e) { 2248 handleRemoteException(e); 2249 return null; 2250 } 2251 } 2252 return ans.value; 2253 } 2254 2255 /** 2256 * Indicates to driver that all the data has to be uploaded urgently 2257 */ getRingBufferData(String ringName)2258 public boolean getRingBufferData(String ringName) { 2259 enter("ringName %").c(ringName).flush(); 2260 synchronized (sLock) { 2261 if (mIWifiChip == null) return boolResult(false); 2262 try { 2263 WifiStatus status = mIWifiChip.forceDumpToDebugRingBuffer(ringName); 2264 return ok(status); 2265 } catch (RemoteException e) { 2266 handleRemoteException(e); 2267 return false; 2268 } 2269 } 2270 } 2271 2272 /** 2273 * request hal to flush ring buffers to files 2274 */ flushRingBufferData()2275 public boolean flushRingBufferData() { 2276 synchronized (sLock) { 2277 if (mIWifiChip == null) return boolResult(false); 2278 android.hardware.wifi.V1_3.IWifiChip iWifiChipV13 = getWifiChipForV1_3Mockable(); 2279 if (iWifiChipV13 != null) { 2280 try { 2281 WifiStatus status = iWifiChipV13.flushRingBufferToFile(); 2282 return ok(status); 2283 } catch (RemoteException e) { 2284 handleRemoteException(e); 2285 return false; 2286 } 2287 } 2288 return false; 2289 } 2290 } 2291 2292 /** 2293 * Request vendor debug info from the firmware 2294 */ getFwMemoryDump()2295 public byte[] getFwMemoryDump() { 2296 class AnswerBox { 2297 public byte[] value; 2298 } 2299 AnswerBox ans = new AnswerBox(); 2300 synchronized (sLock) { 2301 if (mIWifiChip == null) return (null); 2302 try { 2303 mIWifiChip.requestFirmwareDebugDump((status, blob) -> { 2304 if (!ok(status)) return; 2305 ans.value = NativeUtil.byteArrayFromArrayList(blob); 2306 }); 2307 } catch (RemoteException e) { 2308 handleRemoteException(e); 2309 return null; 2310 } 2311 } 2312 return ans.value; 2313 } 2314 2315 /** 2316 * Request vendor debug info from the driver 2317 */ getDriverStateDump()2318 public byte[] getDriverStateDump() { 2319 class AnswerBox { 2320 public byte[] value; 2321 } 2322 AnswerBox ans = new AnswerBox(); 2323 synchronized (sLock) { 2324 if (mIWifiChip == null) return (null); 2325 try { 2326 mIWifiChip.requestDriverDebugDump((status, blob) -> { 2327 if (!ok(status)) return; 2328 ans.value = NativeUtil.byteArrayFromArrayList(blob); 2329 }); 2330 } catch (RemoteException e) { 2331 handleRemoteException(e); 2332 return null; 2333 } 2334 } 2335 return ans.value; 2336 } 2337 2338 /** 2339 * Start packet fate monitoring 2340 * <p> 2341 * Once started, monitoring remains active until HAL is unloaded. 2342 * 2343 * @param ifaceName Name of the interface. 2344 * @return true for success 2345 */ startPktFateMonitoring(@onNull String ifaceName)2346 public boolean startPktFateMonitoring(@NonNull String ifaceName) { 2347 synchronized (sLock) { 2348 IWifiStaIface iface = getStaIface(ifaceName); 2349 if (iface == null) return boolResult(false); 2350 try { 2351 WifiStatus status = iface.startDebugPacketFateMonitoring(); 2352 return ok(status); 2353 } catch (RemoteException e) { 2354 handleRemoteException(e); 2355 return false; 2356 } 2357 } 2358 } 2359 halToFrameworkPktFateFrameType(int type)2360 private byte halToFrameworkPktFateFrameType(int type) { 2361 switch (type) { 2362 case WifiDebugPacketFateFrameType.UNKNOWN: 2363 return WifiLoggerHal.FRAME_TYPE_UNKNOWN; 2364 case WifiDebugPacketFateFrameType.ETHERNET_II: 2365 return WifiLoggerHal.FRAME_TYPE_ETHERNET_II; 2366 case WifiDebugPacketFateFrameType.MGMT_80211: 2367 return WifiLoggerHal.FRAME_TYPE_80211_MGMT; 2368 default: 2369 throw new IllegalArgumentException("bad " + type); 2370 } 2371 } 2372 halToFrameworkRxPktFate(int type)2373 private byte halToFrameworkRxPktFate(int type) { 2374 switch (type) { 2375 case WifiDebugRxPacketFate.SUCCESS: 2376 return WifiLoggerHal.RX_PKT_FATE_SUCCESS; 2377 case WifiDebugRxPacketFate.FW_QUEUED: 2378 return WifiLoggerHal.RX_PKT_FATE_FW_QUEUED; 2379 case WifiDebugRxPacketFate.FW_DROP_FILTER: 2380 return WifiLoggerHal.RX_PKT_FATE_FW_DROP_FILTER; 2381 case WifiDebugRxPacketFate.FW_DROP_INVALID: 2382 return WifiLoggerHal.RX_PKT_FATE_FW_DROP_INVALID; 2383 case WifiDebugRxPacketFate.FW_DROP_NOBUFS: 2384 return WifiLoggerHal.RX_PKT_FATE_FW_DROP_NOBUFS; 2385 case WifiDebugRxPacketFate.FW_DROP_OTHER: 2386 return WifiLoggerHal.RX_PKT_FATE_FW_DROP_OTHER; 2387 case WifiDebugRxPacketFate.DRV_QUEUED: 2388 return WifiLoggerHal.RX_PKT_FATE_DRV_QUEUED; 2389 case WifiDebugRxPacketFate.DRV_DROP_FILTER: 2390 return WifiLoggerHal.RX_PKT_FATE_DRV_DROP_FILTER; 2391 case WifiDebugRxPacketFate.DRV_DROP_INVALID: 2392 return WifiLoggerHal.RX_PKT_FATE_DRV_DROP_INVALID; 2393 case WifiDebugRxPacketFate.DRV_DROP_NOBUFS: 2394 return WifiLoggerHal.RX_PKT_FATE_DRV_DROP_NOBUFS; 2395 case WifiDebugRxPacketFate.DRV_DROP_OTHER: 2396 return WifiLoggerHal.RX_PKT_FATE_DRV_DROP_OTHER; 2397 default: 2398 throw new IllegalArgumentException("bad " + type); 2399 } 2400 } 2401 halToFrameworkTxPktFate(int type)2402 private byte halToFrameworkTxPktFate(int type) { 2403 switch (type) { 2404 case WifiDebugTxPacketFate.ACKED: 2405 return WifiLoggerHal.TX_PKT_FATE_ACKED; 2406 case WifiDebugTxPacketFate.SENT: 2407 return WifiLoggerHal.TX_PKT_FATE_SENT; 2408 case WifiDebugTxPacketFate.FW_QUEUED: 2409 return WifiLoggerHal.TX_PKT_FATE_FW_QUEUED; 2410 case WifiDebugTxPacketFate.FW_DROP_INVALID: 2411 return WifiLoggerHal.TX_PKT_FATE_FW_DROP_INVALID; 2412 case WifiDebugTxPacketFate.FW_DROP_NOBUFS: 2413 return WifiLoggerHal.TX_PKT_FATE_FW_DROP_NOBUFS; 2414 case WifiDebugTxPacketFate.FW_DROP_OTHER: 2415 return WifiLoggerHal.TX_PKT_FATE_FW_DROP_OTHER; 2416 case WifiDebugTxPacketFate.DRV_QUEUED: 2417 return WifiLoggerHal.TX_PKT_FATE_DRV_QUEUED; 2418 case WifiDebugTxPacketFate.DRV_DROP_INVALID: 2419 return WifiLoggerHal.TX_PKT_FATE_DRV_DROP_INVALID; 2420 case WifiDebugTxPacketFate.DRV_DROP_NOBUFS: 2421 return WifiLoggerHal.TX_PKT_FATE_DRV_DROP_NOBUFS; 2422 case WifiDebugTxPacketFate.DRV_DROP_OTHER: 2423 return WifiLoggerHal.TX_PKT_FATE_DRV_DROP_OTHER; 2424 default: 2425 throw new IllegalArgumentException("bad " + type); 2426 } 2427 } 2428 2429 /** 2430 * Retrieve fates of outbound packets 2431 * <p> 2432 * Reports the outbound frames for the most recent association (space allowing). 2433 * 2434 * @param ifaceName Name of the interface. 2435 * @return list of TxFateReports up to size {@link WifiLoggerHal#MAX_FATE_LOG_LEN}, or empty 2436 * list on failure. 2437 */ getTxPktFates(@onNull String ifaceName)2438 public List<TxFateReport> getTxPktFates(@NonNull String ifaceName) { 2439 synchronized (sLock) { 2440 IWifiStaIface iface = getStaIface(ifaceName); 2441 if (iface == null) return objResult(new ArrayList<>()); 2442 try { 2443 List<TxFateReport> reportBufs = new ArrayList<>(); 2444 iface.getDebugTxPacketFates((status, fates) -> { 2445 if (!ok(status)) return; 2446 for (WifiDebugTxPacketFateReport fate : fates) { 2447 if (reportBufs.size() >= WifiLoggerHal.MAX_FATE_LOG_LEN) break; 2448 byte code = halToFrameworkTxPktFate(fate.fate); 2449 long us = fate.frameInfo.driverTimestampUsec; 2450 byte type = halToFrameworkPktFateFrameType(fate.frameInfo.frameType); 2451 byte[] frame = NativeUtil.byteArrayFromArrayList( 2452 fate.frameInfo.frameContent); 2453 reportBufs.add(new TxFateReport(code, us, type, frame)); 2454 } 2455 }); 2456 return reportBufs; 2457 } catch (RemoteException e) { 2458 handleRemoteException(e); 2459 return new ArrayList<>(); 2460 } 2461 } 2462 } 2463 2464 /** 2465 * Retrieve fates of inbound packets 2466 * <p> 2467 * Reports the inbound frames for the most recent association (space allowing). 2468 * 2469 * @param ifaceName Name of the interface. 2470 * @return list of RxFateReports up to size {@link WifiLoggerHal#MAX_FATE_LOG_LEN}, or empty 2471 * list on failure. 2472 */ getRxPktFates(@onNull String ifaceName)2473 public List<RxFateReport> getRxPktFates(@NonNull String ifaceName) { 2474 synchronized (sLock) { 2475 IWifiStaIface iface = getStaIface(ifaceName); 2476 if (iface == null) return objResult(new ArrayList<>()); 2477 try { 2478 List<RxFateReport> reportBufs = new ArrayList<>(); 2479 iface.getDebugRxPacketFates((status, fates) -> { 2480 if (!ok(status)) return; 2481 for (WifiDebugRxPacketFateReport fate : fates) { 2482 if (reportBufs.size() >= WifiLoggerHal.MAX_FATE_LOG_LEN) break; 2483 byte code = halToFrameworkRxPktFate(fate.fate); 2484 long us = fate.frameInfo.driverTimestampUsec; 2485 byte type = halToFrameworkPktFateFrameType(fate.frameInfo.frameType); 2486 byte[] frame = NativeUtil.byteArrayFromArrayList( 2487 fate.frameInfo.frameContent); 2488 reportBufs.add(new RxFateReport(code, us, type, frame)); 2489 } 2490 }); 2491 return reportBufs; 2492 } catch (RemoteException e) { 2493 handleRemoteException(e); 2494 return new ArrayList<>(); 2495 } 2496 } 2497 } 2498 2499 /** 2500 * Start sending the specified keep alive packets periodically. 2501 * 2502 * @param ifaceName Name of the interface. 2503 * @param slot 2504 * @param srcMac 2505 * @param dstMac 2506 * @param keepAlivePacket 2507 * @param protocol 2508 * @param periodInMs 2509 * @return 0 for success, -1 for error 2510 */ startSendingOffloadedPacket( @onNull String ifaceName, int slot, byte[] srcMac, byte[] dstMac, byte[] packet, int protocol, int periodInMs)2511 public int startSendingOffloadedPacket( 2512 @NonNull String ifaceName, int slot, byte[] srcMac, byte[] dstMac, 2513 byte[] packet, int protocol, int periodInMs) { 2514 enter("slot=% periodInMs=%").c(slot).c(periodInMs).flush(); 2515 2516 ArrayList<Byte> data = NativeUtil.byteArrayToArrayList(packet); 2517 2518 synchronized (sLock) { 2519 IWifiStaIface iface = getStaIface(ifaceName); 2520 if (iface == null) return -1; 2521 try { 2522 WifiStatus status = iface.startSendingKeepAlivePackets( 2523 slot, 2524 data, 2525 (short) protocol, 2526 srcMac, 2527 dstMac, 2528 periodInMs); 2529 if (!ok(status)) return -1; 2530 return 0; 2531 } catch (RemoteException e) { 2532 handleRemoteException(e); 2533 return -1; 2534 } 2535 } 2536 } 2537 2538 /** 2539 * Stop sending the specified keep alive packets. 2540 * 2541 * @param ifaceName Name of the interface. 2542 * @param slot id - same as startSendingOffloadedPacket call. 2543 * @return 0 for success, -1 for error 2544 */ stopSendingOffloadedPacket(@onNull String ifaceName, int slot)2545 public int stopSendingOffloadedPacket(@NonNull String ifaceName, int slot) { 2546 enter("slot=%").c(slot).flush(); 2547 2548 synchronized (sLock) { 2549 IWifiStaIface iface = getStaIface(ifaceName); 2550 if (iface == null) return -1; 2551 try { 2552 WifiStatus status = iface.stopSendingKeepAlivePackets(slot); 2553 if (!ok(status)) return -1; 2554 return 0; 2555 } catch (RemoteException e) { 2556 handleRemoteException(e); 2557 return -1; 2558 } 2559 } 2560 } 2561 2562 /** 2563 * A fixed cmdId for our RssiMonitoring (we only do one at a time) 2564 */ 2565 @VisibleForTesting 2566 static final int sRssiMonCmdId = 7551; 2567 2568 /** 2569 * Our client's handler 2570 */ 2571 private WifiNative.WifiRssiEventHandler mWifiRssiEventHandler; 2572 2573 /** 2574 * Start RSSI monitoring on the currently connected access point. 2575 * 2576 * @param ifaceName Name of the interface. 2577 * @param maxRssi Maximum RSSI threshold. 2578 * @param minRssi Minimum RSSI threshold. 2579 * @param rssiEventHandler Called when RSSI goes above maxRssi or below minRssi 2580 * @return 0 for success, -1 for failure 2581 */ startRssiMonitoring(@onNull String ifaceName, byte maxRssi, byte minRssi, WifiNative.WifiRssiEventHandler rssiEventHandler)2582 public int startRssiMonitoring(@NonNull String ifaceName, byte maxRssi, byte minRssi, 2583 WifiNative.WifiRssiEventHandler rssiEventHandler) { 2584 enter("maxRssi=% minRssi=%").c(maxRssi).c(minRssi).flush(); 2585 if (maxRssi <= minRssi) return -1; 2586 if (rssiEventHandler == null) return -1; 2587 synchronized (sLock) { 2588 IWifiStaIface iface = getStaIface(ifaceName); 2589 if (iface == null) return -1; 2590 try { 2591 iface.stopRssiMonitoring(sRssiMonCmdId); 2592 WifiStatus status; 2593 status = iface.startRssiMonitoring(sRssiMonCmdId, maxRssi, minRssi); 2594 if (!ok(status)) return -1; 2595 mWifiRssiEventHandler = rssiEventHandler; 2596 return 0; 2597 } catch (RemoteException e) { 2598 handleRemoteException(e); 2599 return -1; 2600 } 2601 } 2602 } 2603 2604 /** 2605 * Stop RSSI monitoring 2606 * 2607 * @param ifaceName Name of the interface. 2608 * @return 0 for success, -1 for failure 2609 */ stopRssiMonitoring(@onNull String ifaceName)2610 public int stopRssiMonitoring(@NonNull String ifaceName) { 2611 synchronized (sLock) { 2612 mWifiRssiEventHandler = null; 2613 IWifiStaIface iface = getStaIface(ifaceName); 2614 if (iface == null) return -1; 2615 try { 2616 WifiStatus status = iface.stopRssiMonitoring(sRssiMonCmdId); 2617 if (!ok(status)) return -1; 2618 return 0; 2619 } catch (RemoteException e) { 2620 handleRemoteException(e); 2621 return -1; 2622 } 2623 } 2624 } 2625 2626 //TODO - belongs in NativeUtil intsFromArrayList(ArrayList<Integer> a)2627 private static int[] intsFromArrayList(ArrayList<Integer> a) { 2628 if (a == null) return null; 2629 int[] b = new int[a.size()]; 2630 int i = 0; 2631 for (Integer e : a) b[i++] = e; 2632 return b; 2633 } 2634 2635 /** 2636 * Translates from Hal version of wake reason stats to the framework version of same 2637 * 2638 * @param h - Hal version of wake reason stats 2639 * @return framework version of same 2640 */ halToFrameworkWakeReasons( WifiDebugHostWakeReasonStats h)2641 private static WlanWakeReasonAndCounts halToFrameworkWakeReasons( 2642 WifiDebugHostWakeReasonStats h) { 2643 if (h == null) return null; 2644 WlanWakeReasonAndCounts ans = new WlanWakeReasonAndCounts(); 2645 ans.totalCmdEventWake = h.totalCmdEventWakeCnt; 2646 ans.totalDriverFwLocalWake = h.totalDriverFwLocalWakeCnt; 2647 ans.totalRxDataWake = h.totalRxPacketWakeCnt; 2648 ans.rxUnicast = h.rxPktWakeDetails.rxUnicastCnt; 2649 ans.rxMulticast = h.rxPktWakeDetails.rxMulticastCnt; 2650 ans.rxBroadcast = h.rxPktWakeDetails.rxBroadcastCnt; 2651 ans.icmp = h.rxIcmpPkWakeDetails.icmpPkt; 2652 ans.icmp6 = h.rxIcmpPkWakeDetails.icmp6Pkt; 2653 ans.icmp6Ra = h.rxIcmpPkWakeDetails.icmp6Ra; 2654 ans.icmp6Na = h.rxIcmpPkWakeDetails.icmp6Na; 2655 ans.icmp6Ns = h.rxIcmpPkWakeDetails.icmp6Ns; 2656 ans.ipv4RxMulticast = h.rxMulticastPkWakeDetails.ipv4RxMulticastAddrCnt; 2657 ans.ipv6Multicast = h.rxMulticastPkWakeDetails.ipv6RxMulticastAddrCnt; 2658 ans.otherRxMulticast = h.rxMulticastPkWakeDetails.otherRxMulticastAddrCnt; 2659 ans.cmdEventWakeCntArray = intsFromArrayList(h.cmdEventWakeCntPerType); 2660 ans.driverFWLocalWakeCntArray = intsFromArrayList(h.driverFwLocalWakeCntPerType); 2661 return ans; 2662 } 2663 2664 /** 2665 * Fetch the host wakeup reasons stats from wlan driver. 2666 * 2667 * @return the |WlanWakeReasonAndCounts| from the wlan driver, or null on failure. 2668 */ getWlanWakeReasonCount()2669 public WlanWakeReasonAndCounts getWlanWakeReasonCount() { 2670 class AnswerBox { 2671 public WifiDebugHostWakeReasonStats value = null; 2672 } 2673 AnswerBox ans = new AnswerBox(); 2674 synchronized (sLock) { 2675 if (mIWifiChip == null) return null; 2676 try { 2677 mIWifiChip.getDebugHostWakeReasonStats((status, stats) -> { 2678 if (ok(status)) { 2679 ans.value = stats; 2680 } 2681 }); 2682 return halToFrameworkWakeReasons(ans.value); 2683 } catch (RemoteException e) { 2684 handleRemoteException(e); 2685 return null; 2686 } 2687 } 2688 } 2689 2690 /** 2691 * Enable/Disable Neighbour discovery offload functionality in the firmware. 2692 * 2693 * @param ifaceName Name of the interface. 2694 * @param enabled true to enable, false to disable. 2695 * @return true for success, false for failure 2696 */ configureNeighborDiscoveryOffload(@onNull String ifaceName, boolean enabled)2697 public boolean configureNeighborDiscoveryOffload(@NonNull String ifaceName, boolean enabled) { 2698 enter("enabled=%").c(enabled).flush(); 2699 synchronized (sLock) { 2700 IWifiStaIface iface = getStaIface(ifaceName); 2701 if (iface == null) return boolResult(false); 2702 try { 2703 WifiStatus status = iface.enableNdOffload(enabled); 2704 if (!ok(status)) return false; 2705 } catch (RemoteException e) { 2706 handleRemoteException(e); 2707 return false; 2708 } 2709 } 2710 return true; 2711 } 2712 2713 // Firmware roaming control. 2714 2715 /** 2716 * Query the firmware roaming capabilities. 2717 * 2718 * @param ifaceName Name of the interface. 2719 * @return capabilities object on success, null otherwise. 2720 */ 2721 @Nullable getRoamingCapabilities(@onNull String ifaceName)2722 public WifiNative.RoamingCapabilities getRoamingCapabilities(@NonNull String ifaceName) { 2723 synchronized (sLock) { 2724 IWifiStaIface iface = getStaIface(ifaceName); 2725 if (iface == null) return nullResult(); 2726 try { 2727 Mutable<Boolean> ok = new Mutable<>(false); 2728 WifiNative.RoamingCapabilities out = new WifiNative.RoamingCapabilities(); 2729 iface.getRoamingCapabilities((status, cap) -> { 2730 if (!ok(status)) return; 2731 out.maxBlocklistSize = cap.maxBlacklistSize; 2732 out.maxAllowlistSize = cap.maxWhitelistSize; 2733 ok.value = true; 2734 }); 2735 if (ok.value) { 2736 return out; 2737 } else { 2738 return null; 2739 } 2740 } catch (RemoteException e) { 2741 handleRemoteException(e); 2742 return null; 2743 } 2744 } 2745 } 2746 2747 /** 2748 * Enable/disable firmware roaming. 2749 * 2750 * @param ifaceName Name of the interface. 2751 * @param state the intended roaming state 2752 * @return SET_FIRMWARE_ROAMING_SUCCESS, SET_FIRMWARE_ROAMING_FAILURE, 2753 * or SET_FIRMWARE_ROAMING_BUSY 2754 */ enableFirmwareRoaming(@onNull String ifaceName, @WifiNative.RoamingEnableState int state)2755 public @WifiNative.RoamingEnableStatus int enableFirmwareRoaming(@NonNull String ifaceName, 2756 @WifiNative.RoamingEnableState int state) { 2757 synchronized (sLock) { 2758 IWifiStaIface iface = getStaIface(ifaceName); 2759 if (iface == null) return WifiNative.SET_FIRMWARE_ROAMING_FAILURE; 2760 try { 2761 byte val; 2762 switch (state) { 2763 case WifiNative.DISABLE_FIRMWARE_ROAMING: 2764 val = StaRoamingState.DISABLED; 2765 break; 2766 case WifiNative.ENABLE_FIRMWARE_ROAMING: 2767 val = StaRoamingState.ENABLED; 2768 break; 2769 default: 2770 mLog.err("enableFirmwareRoaming invalid argument %").c(state).flush(); 2771 return WifiNative.SET_FIRMWARE_ROAMING_FAILURE; 2772 } 2773 WifiStatus status = iface.setRoamingState(val); 2774 if (ok(status)) { 2775 return WifiNative.SET_FIRMWARE_ROAMING_SUCCESS; 2776 } else if (status.code == WifiStatusCode.ERROR_BUSY) { 2777 return WifiNative.SET_FIRMWARE_ROAMING_BUSY; 2778 } else { 2779 return WifiNative.SET_FIRMWARE_ROAMING_FAILURE; 2780 } 2781 } catch (RemoteException e) { 2782 handleRemoteException(e); 2783 return WifiNative.SET_FIRMWARE_ROAMING_FAILURE; 2784 } 2785 } 2786 } 2787 2788 /** 2789 * Set firmware roaming configurations. 2790 * 2791 * @param ifaceName Name of the interface. 2792 * @param config new roaming configuration object 2793 * @return true for success; false for failure 2794 */ configureRoaming(@onNull String ifaceName, WifiNative.RoamingConfig config)2795 public boolean configureRoaming(@NonNull String ifaceName, WifiNative.RoamingConfig config) { 2796 synchronized (sLock) { 2797 IWifiStaIface iface = getStaIface(ifaceName); 2798 if (iface == null) return boolResult(false); 2799 try { 2800 StaRoamingConfig roamingConfig = new StaRoamingConfig(); 2801 2802 // parse the blacklist BSSIDs if any 2803 if (config.blocklistBssids != null) { 2804 for (String bssid : config.blocklistBssids) { 2805 byte[] mac = NativeUtil.macAddressToByteArray(bssid); 2806 roamingConfig.bssidBlacklist.add(mac); 2807 } 2808 } 2809 2810 // parse the whitelist SSIDs if any 2811 if (config.allowlistSsids != null) { 2812 for (String ssidStr : config.allowlistSsids) { 2813 byte[] ssid = NativeUtil.byteArrayFromArrayList( 2814 NativeUtil.decodeSsid(ssidStr)); 2815 // HIDL code is throwing InvalidArgumentException when ssidWhitelist has 2816 // SSIDs with less than 32 byte length this is due to HAL definition of 2817 // SSID declared it as 32-byte fixed length array. Thus pad additional 2818 // bytes with 0's to pass SSIDs as byte arrays of 32 length 2819 byte[] ssid_32 = new byte[32]; 2820 for (int i = 0; i < ssid.length; i++) { 2821 ssid_32[i] = ssid[i]; 2822 } 2823 roamingConfig.ssidWhitelist.add(ssid_32); 2824 } 2825 } 2826 2827 WifiStatus status = iface.configureRoaming(roamingConfig); 2828 if (!ok(status)) return false; 2829 } catch (RemoteException e) { 2830 handleRemoteException(e); 2831 return false; 2832 } catch (IllegalArgumentException e) { 2833 mLog.err("Illegal argument for roaming configuration").c(e.toString()).flush(); 2834 return false; 2835 } 2836 return true; 2837 } 2838 } 2839 2840 /** 2841 * Method to mock out the V1_1 IWifiChip retrieval in unit tests. 2842 * 2843 * @return 1.1 IWifiChip object if the device is running the 1.1 wifi hal service, null 2844 * otherwise. 2845 */ getWifiChipForV1_1Mockable()2846 protected android.hardware.wifi.V1_1.IWifiChip getWifiChipForV1_1Mockable() { 2847 if (mIWifiChip == null) return null; 2848 return android.hardware.wifi.V1_1.IWifiChip.castFrom(mIWifiChip); 2849 } 2850 2851 /** 2852 * Method to mock out the V1_2 IWifiChip retrieval in unit tests. 2853 * 2854 * @return 1.2 IWifiChip object if the device is running the 1.2 wifi hal service, null 2855 * otherwise. 2856 */ getWifiChipForV1_2Mockable()2857 protected android.hardware.wifi.V1_2.IWifiChip getWifiChipForV1_2Mockable() { 2858 if (mIWifiChip == null) return null; 2859 return android.hardware.wifi.V1_2.IWifiChip.castFrom(mIWifiChip); 2860 } 2861 2862 /** 2863 * Method to mock out the V1_3 IWifiChip retrieval in unit tests. 2864 * 2865 * @return 1.3 IWifiChip object if the device is running the 1.3 wifi hal service, null 2866 * otherwise. 2867 */ getWifiChipForV1_3Mockable()2868 protected android.hardware.wifi.V1_3.IWifiChip getWifiChipForV1_3Mockable() { 2869 if (mIWifiChip == null) return null; 2870 return android.hardware.wifi.V1_3.IWifiChip.castFrom(mIWifiChip); 2871 } 2872 2873 /** 2874 * Method to mock out the V1_4 IWifiChip retrieval in unit tests. 2875 * 2876 * @return 1.4 IWifiChip object if the device is running the 1.4 wifi hal service, null 2877 * otherwise. 2878 */ getWifiChipForV1_4Mockable()2879 protected android.hardware.wifi.V1_4.IWifiChip getWifiChipForV1_4Mockable() { 2880 if (mIWifiChip == null) return null; 2881 return android.hardware.wifi.V1_4.IWifiChip.castFrom(mIWifiChip); 2882 } 2883 2884 /** 2885 * Method to mock out the V1_5 IWifiChip retrieval in unit tests. 2886 * 2887 * @return 1.5 IWifiChip object if the device is running the 1.5 wifi hal service, null 2888 * otherwise. 2889 */ getWifiChipForV1_5Mockable()2890 protected android.hardware.wifi.V1_5.IWifiChip getWifiChipForV1_5Mockable() { 2891 if (mIWifiChip == null) return null; 2892 return android.hardware.wifi.V1_5.IWifiChip.castFrom(mIWifiChip); 2893 } 2894 2895 /** 2896 * Method to mock out the V1_2 IWifiStaIface retrieval in unit tests. 2897 * 2898 * @param ifaceName Name of the interface 2899 * @return 1.2 IWifiStaIface object if the device is running the 1.2 wifi hal service, null 2900 * otherwise. 2901 */ getWifiStaIfaceForV1_2Mockable( @onNull String ifaceName)2902 protected android.hardware.wifi.V1_2.IWifiStaIface getWifiStaIfaceForV1_2Mockable( 2903 @NonNull String ifaceName) { 2904 IWifiStaIface iface = getStaIface(ifaceName); 2905 if (iface == null) return null; 2906 return android.hardware.wifi.V1_2.IWifiStaIface.castFrom(iface); 2907 } 2908 2909 /** 2910 * Method to mock out the V1_3 IWifiStaIface retrieval in unit tests. 2911 * 2912 * @param ifaceName Name of the interface 2913 * @return 1.3 IWifiStaIface object if the device is running the 1.3 wifi hal service, null 2914 * otherwise. 2915 */ getWifiStaIfaceForV1_3Mockable( @onNull String ifaceName)2916 protected android.hardware.wifi.V1_3.IWifiStaIface getWifiStaIfaceForV1_3Mockable( 2917 @NonNull String ifaceName) { 2918 IWifiStaIface iface = getStaIface(ifaceName); 2919 if (iface == null) return null; 2920 return android.hardware.wifi.V1_3.IWifiStaIface.castFrom(iface); 2921 } 2922 2923 /** 2924 * Method to mock out the V1_5 IWifiStaIface retrieval in unit tests. 2925 * 2926 * @param ifaceName Name of the interface 2927 * @return 1.5 IWifiStaIface object if the device is running the 1.5 wifi hal service, null 2928 * otherwise. 2929 */ getWifiStaIfaceForV1_5Mockable( @onNull String ifaceName)2930 protected android.hardware.wifi.V1_5.IWifiStaIface getWifiStaIfaceForV1_5Mockable( 2931 @NonNull String ifaceName) { 2932 IWifiStaIface iface = getStaIface(ifaceName); 2933 if (iface == null) return null; 2934 return android.hardware.wifi.V1_5.IWifiStaIface.castFrom(iface); 2935 } 2936 getWifiApIfaceForV1_4Mockable( String ifaceName)2937 protected android.hardware.wifi.V1_4.IWifiApIface getWifiApIfaceForV1_4Mockable( 2938 String ifaceName) { 2939 IWifiApIface iface = getApIface(ifaceName); 2940 if (iface == null) return null; 2941 return android.hardware.wifi.V1_4.IWifiApIface.castFrom(iface); 2942 } 2943 getWifiApIfaceForV1_5Mockable( String ifaceName)2944 protected android.hardware.wifi.V1_5.IWifiApIface getWifiApIfaceForV1_5Mockable( 2945 String ifaceName) { 2946 IWifiApIface iface = getApIface(ifaceName); 2947 if (iface == null) return null; 2948 return android.hardware.wifi.V1_5.IWifiApIface.castFrom(iface); 2949 } 2950 2951 /** 2952 * sarPowerBackoffRequired_1_1() 2953 * This method checks if we need to backoff wifi Tx power due to SAR requirements. 2954 * It handles the case when the device is running the V1_1 version of WifiChip HAL 2955 * In that HAL version, it is required to perform wifi Tx power backoff only if 2956 * a voice call is ongoing. 2957 */ sarPowerBackoffRequired_1_1(SarInfo sarInfo)2958 private boolean sarPowerBackoffRequired_1_1(SarInfo sarInfo) { 2959 /* As long as no voice call is active (in case voice call is supported), 2960 * no backoff is needed */ 2961 if (sarInfo.sarVoiceCallSupported) { 2962 return (sarInfo.isVoiceCall || sarInfo.isEarPieceActive); 2963 } else { 2964 return false; 2965 } 2966 } 2967 2968 /** 2969 * frameworkToHalTxPowerScenario_1_1() 2970 * This method maps the information inside the SarInfo instance into a SAR scenario 2971 * when device is running the V1_1 version of WifiChip HAL. 2972 * In this HAL version, only one scenario is defined which is for VOICE_CALL (if voice call is 2973 * supported). 2974 * Otherwise, an exception is thrown. 2975 */ frameworkToHalTxPowerScenario_1_1(SarInfo sarInfo)2976 private int frameworkToHalTxPowerScenario_1_1(SarInfo sarInfo) { 2977 if (sarInfo.sarVoiceCallSupported && (sarInfo.isVoiceCall || sarInfo.isEarPieceActive)) { 2978 return android.hardware.wifi.V1_1.IWifiChip.TxPowerScenario.VOICE_CALL; 2979 } else { 2980 throw new IllegalArgumentException("bad scenario: voice call not active/supported"); 2981 } 2982 } 2983 2984 /** 2985 * sarPowerBackoffRequired_1_2() 2986 * This method checks if we need to backoff wifi Tx power due to SAR requirements. 2987 * It handles the case when the device is running the V1_2 version of WifiChip HAL 2988 */ sarPowerBackoffRequired_1_2(SarInfo sarInfo)2989 private boolean sarPowerBackoffRequired_1_2(SarInfo sarInfo) { 2990 if (sarInfo.sarSapSupported && sarInfo.isWifiSapEnabled) { 2991 return true; 2992 } 2993 if (sarInfo.sarVoiceCallSupported && (sarInfo.isVoiceCall || sarInfo.isEarPieceActive)) { 2994 return true; 2995 } 2996 return false; 2997 } 2998 2999 /** 3000 * frameworkToHalTxPowerScenario_1_2() 3001 * This method maps the information inside the SarInfo instance into a SAR scenario 3002 * when device is running the V1_2 version of WifiChip HAL. 3003 * If SAR SoftAP input is supported, 3004 * we make these assumptions: 3005 * - All voice calls are treated as if device is near the head. 3006 * - SoftAP scenario is treated as if device is near the body. 3007 * In case SoftAP is not supported, then we should revert to the V1_1 HAL 3008 * behavior, and the only valid scenario would be when a voice call is ongoing. 3009 */ frameworkToHalTxPowerScenario_1_2(SarInfo sarInfo)3010 private int frameworkToHalTxPowerScenario_1_2(SarInfo sarInfo) { 3011 if (sarInfo.sarSapSupported && sarInfo.sarVoiceCallSupported) { 3012 if (sarInfo.isVoiceCall || sarInfo.isEarPieceActive) { 3013 return android.hardware.wifi.V1_2.IWifiChip 3014 .TxPowerScenario.ON_HEAD_CELL_ON; 3015 } else if (sarInfo.isWifiSapEnabled) { 3016 return android.hardware.wifi.V1_2.IWifiChip 3017 .TxPowerScenario.ON_BODY_CELL_ON; 3018 } else { 3019 throw new IllegalArgumentException("bad scenario: no voice call/softAP active"); 3020 } 3021 } else if (sarInfo.sarVoiceCallSupported) { 3022 /* SAR SoftAP input not supported, act like V1_1 */ 3023 if (sarInfo.isVoiceCall || sarInfo.isEarPieceActive) { 3024 return android.hardware.wifi.V1_1.IWifiChip.TxPowerScenario.VOICE_CALL; 3025 } else { 3026 throw new IllegalArgumentException("bad scenario: voice call not active"); 3027 } 3028 } else { 3029 throw new IllegalArgumentException("Invalid case: voice call not supported"); 3030 } 3031 } 3032 3033 /** 3034 * Select one of the pre-configured TX power level scenarios or reset it back to normal. 3035 * Primarily used for meeting SAR requirements during voice calls. 3036 * 3037 * Note: If it was found out that the scenario to be reported is the same as last reported one, 3038 * then exit with success. 3039 * This is to handle the case when some HAL versions deal with different inputs equally, 3040 * in that case, we should not call the hal unless there is a change in scenario. 3041 * Note: It is assumed that this method is only called if SAR is enabled. The logic of whether 3042 * to call it or not resides in SarManager class. 3043 * 3044 * @param sarInfo The collection of inputs to select the SAR scenario. 3045 * @return true for success; false for failure or if the HAL version does not support this API. 3046 */ selectTxPowerScenario(SarInfo sarInfo)3047 public boolean selectTxPowerScenario(SarInfo sarInfo) { 3048 synchronized (sLock) { 3049 // First attempt to get a V_1_2 instance of the Wifi HAL. 3050 android.hardware.wifi.V1_2.IWifiChip iWifiChipV12 = getWifiChipForV1_2Mockable(); 3051 if (iWifiChipV12 != null) { 3052 return selectTxPowerScenario_1_2(iWifiChipV12, sarInfo); 3053 } 3054 3055 // Now attempt to get a V_1_1 instance of the Wifi HAL. 3056 android.hardware.wifi.V1_1.IWifiChip iWifiChipV11 = getWifiChipForV1_1Mockable(); 3057 if (iWifiChipV11 != null) { 3058 return selectTxPowerScenario_1_1(iWifiChipV11, sarInfo); 3059 } 3060 3061 // HAL version does not support SAR 3062 return false; 3063 } 3064 } 3065 selectTxPowerScenario_1_1( android.hardware.wifi.V1_1.IWifiChip iWifiChip, SarInfo sarInfo)3066 private boolean selectTxPowerScenario_1_1( 3067 android.hardware.wifi.V1_1.IWifiChip iWifiChip, SarInfo sarInfo) { 3068 WifiStatus status; 3069 try { 3070 if (sarPowerBackoffRequired_1_1(sarInfo)) { 3071 // Power backoff is needed, so calculate the required scenario, 3072 // and attempt to set it. 3073 int halScenario = frameworkToHalTxPowerScenario_1_1(sarInfo); 3074 if (sarInfo.setSarScenarioNeeded(halScenario)) { 3075 status = iWifiChip.selectTxPowerScenario(halScenario); 3076 if (ok(status)) { 3077 mLog.d("Setting SAR scenario to " + halScenario); 3078 return true; 3079 } else { 3080 mLog.e("Failed to set SAR scenario to " + halScenario); 3081 return false; 3082 } 3083 } 3084 3085 // Reaching here means setting SAR scenario would be redundant, 3086 // do nothing and return with success. 3087 return true; 3088 } 3089 3090 // We don't need to perform power backoff, so attempt to reset SAR scenario. 3091 if (sarInfo.resetSarScenarioNeeded()) { 3092 status = iWifiChip.resetTxPowerScenario(); 3093 if (ok(status)) { 3094 mLog.d("Resetting SAR scenario"); 3095 return true; 3096 } else { 3097 mLog.e("Failed to reset SAR scenario"); 3098 return false; 3099 } 3100 } 3101 3102 // Resetting SAR scenario would be redundant, 3103 // do nothing and return with success. 3104 return true; 3105 } catch (RemoteException e) { 3106 handleRemoteException(e); 3107 return false; 3108 } catch (IllegalArgumentException e) { 3109 mLog.err("Illegal argument for selectTxPowerScenario_1_1()").c(e.toString()).flush(); 3110 return false; 3111 } 3112 } 3113 selectTxPowerScenario_1_2( android.hardware.wifi.V1_2.IWifiChip iWifiChip, SarInfo sarInfo)3114 private boolean selectTxPowerScenario_1_2( 3115 android.hardware.wifi.V1_2.IWifiChip iWifiChip, SarInfo sarInfo) { 3116 WifiStatus status; 3117 try { 3118 if (sarPowerBackoffRequired_1_2(sarInfo)) { 3119 // Power backoff is needed, so calculate the required scenario, 3120 // and attempt to set it. 3121 int halScenario = frameworkToHalTxPowerScenario_1_2(sarInfo); 3122 if (sarInfo.setSarScenarioNeeded(halScenario)) { 3123 status = iWifiChip.selectTxPowerScenario_1_2(halScenario); 3124 if (ok(status)) { 3125 mLog.d("Setting SAR scenario to " + halScenario); 3126 return true; 3127 } else { 3128 mLog.e("Failed to set SAR scenario to " + halScenario); 3129 return false; 3130 } 3131 } 3132 3133 // Reaching here means setting SAR scenario would be redundant, 3134 // do nothing and return with success. 3135 return true; 3136 } 3137 3138 // We don't need to perform power backoff, so attempt to reset SAR scenario. 3139 if (sarInfo.resetSarScenarioNeeded()) { 3140 status = iWifiChip.resetTxPowerScenario(); 3141 if (ok(status)) { 3142 mLog.d("Resetting SAR scenario"); 3143 return true; 3144 } else { 3145 mLog.e("Failed to reset SAR scenario"); 3146 return false; 3147 } 3148 } 3149 3150 // Resetting SAR scenario would be redundant, 3151 // do nothing and return with success. 3152 return true; 3153 } catch (RemoteException e) { 3154 handleRemoteException(e); 3155 return false; 3156 } catch (IllegalArgumentException e) { 3157 mLog.err("Illegal argument for selectTxPowerScenario_1_2()").c(e.toString()).flush(); 3158 return false; 3159 } 3160 } 3161 3162 /** 3163 * Enable/Disable low-latency mode 3164 * 3165 * @param enabled true to enable low-latency mode, false to disable it 3166 */ setLowLatencyMode(boolean enabled)3167 public boolean setLowLatencyMode(boolean enabled) { 3168 synchronized (sLock) { 3169 android.hardware.wifi.V1_3.IWifiChip iWifiChipV13 = getWifiChipForV1_3Mockable(); 3170 if (iWifiChipV13 != null) { 3171 try { 3172 int mode; 3173 if (enabled) { 3174 mode = android.hardware.wifi.V1_3.IWifiChip.LatencyMode.LOW; 3175 } else { 3176 mode = android.hardware.wifi.V1_3.IWifiChip.LatencyMode.NORMAL; 3177 } 3178 3179 WifiStatus status = iWifiChipV13.setLatencyMode(mode); 3180 if (ok(status)) { 3181 mVerboseLog.d("Setting low-latency mode to " + enabled); 3182 return true; 3183 } else { 3184 mLog.e("Failed to set low-latency mode to " + enabled); 3185 return false; 3186 } 3187 } catch (RemoteException e) { 3188 handleRemoteException(e); 3189 return false; 3190 } 3191 } 3192 3193 // HAL version does not support this api 3194 return false; 3195 } 3196 } 3197 3198 /** 3199 * Returns whether STA + AP concurrency is supported or not. 3200 */ isStaApConcurrencySupported()3201 public boolean isStaApConcurrencySupported() { 3202 synchronized (sLock) { 3203 return mHalDeviceManager.canSupportIfaceCombo(new SparseArray<Integer>() {{ 3204 put(IfaceType.STA, 1); 3205 put(IfaceType.AP, 1); 3206 }}); 3207 } 3208 } 3209 3210 /** 3211 * Returns whether STA + STA concurrency is supported or not. 3212 */ 3213 public boolean isStaStaConcurrencySupported() { 3214 synchronized (sLock) { 3215 return mHalDeviceManager.canSupportIfaceCombo(new SparseArray<Integer>() {{ 3216 put(IfaceType.STA, 2); 3217 }}); 3218 } 3219 } 3220 3221 /** 3222 * Returns whether a new AP iface can be created or not. 3223 */ 3224 public boolean isItPossibleToCreateApIface(@NonNull WorkSource requestorWs) { 3225 synchronized (sLock) { 3226 return mHalDeviceManager.isItPossibleToCreateIface(IfaceType.AP, requestorWs); 3227 } 3228 } 3229 3230 /** 3231 * Returns whether a new STA iface can be created or not. 3232 */ 3233 public boolean isItPossibleToCreateStaIface(@NonNull WorkSource requestorWs) { 3234 synchronized (sLock) { 3235 return mHalDeviceManager.isItPossibleToCreateIface(IfaceType.STA, requestorWs); 3236 } 3237 3238 } 3239 /** 3240 * Set primary connection when multiple STA ifaces are active. 3241 * 3242 * @param ifaceName Name of the interface. 3243 * @return true for success 3244 */ 3245 public boolean setMultiStaPrimaryConnection(@NonNull String ifaceName) { 3246 if (TextUtils.isEmpty(ifaceName)) return boolResult(false); 3247 synchronized (sLock) { 3248 try { 3249 android.hardware.wifi.V1_5.IWifiChip iWifiChipV15 = getWifiChipForV1_5Mockable(); 3250 if (iWifiChipV15 == null) return boolResult(false); 3251 WifiStatus status = iWifiChipV15.setMultiStaPrimaryConnection(ifaceName); 3252 if (!ok(status)) return false; 3253 return true; 3254 } catch (RemoteException e) { 3255 handleRemoteException(e); 3256 return false; 3257 } 3258 } 3259 } 3260 3261 private byte frameworkMultiStaUseCaseToHidl(@WifiNative.MultiStaUseCase int useCase) 3262 throws IllegalArgumentException { 3263 switch (useCase) { 3264 case WifiNative.DUAL_STA_TRANSIENT_PREFER_PRIMARY: 3265 return MultiStaUseCase.DUAL_STA_TRANSIENT_PREFER_PRIMARY; 3266 case WifiNative.DUAL_STA_NON_TRANSIENT_UNBIASED: 3267 return MultiStaUseCase.DUAL_STA_NON_TRANSIENT_UNBIASED; 3268 default: 3269 throw new IllegalArgumentException("Invalid use case " + useCase); 3270 } 3271 } 3272 3273 /** 3274 * Set use-case when multiple STA ifaces are active. 3275 * 3276 * @param useCase one of the use cases. 3277 * @return true for success 3278 */ 3279 public boolean setMultiStaUseCase(@WifiNative.MultiStaUseCase int useCase) { 3280 synchronized (sLock) { 3281 try { 3282 android.hardware.wifi.V1_5.IWifiChip iWifiChipV15 = getWifiChipForV1_5Mockable(); 3283 if (iWifiChipV15 == null) return boolResult(false); 3284 WifiStatus status = iWifiChipV15.setMultiStaUseCase( 3285 frameworkMultiStaUseCaseToHidl(useCase)); 3286 if (!ok(status)) return false; 3287 return true; 3288 } catch (IllegalArgumentException e) { 3289 mLog.e("Invalid use case " + e); 3290 return boolResult(false); 3291 } catch (RemoteException e) { 3292 handleRemoteException(e); 3293 return false; 3294 } 3295 } 3296 } 3297 3298 /** 3299 * Notify scan mode state to driver to save power in scan-only mode. 3300 * 3301 * @param ifaceName Name of the interface. 3302 * @param enable whether is in scan-only mode 3303 * @return true for success 3304 */ 3305 public boolean setScanMode(@NonNull String ifaceName, boolean enable) { 3306 synchronized (sLock) { 3307 try { 3308 android.hardware.wifi.V1_5.IWifiStaIface iface = 3309 getWifiStaIfaceForV1_5Mockable(ifaceName); 3310 if (iface != null) { 3311 WifiStatus status = iface.setScanMode(enable); 3312 if (!ok(status)) return false; 3313 return true; 3314 } 3315 return false; 3316 } catch (RemoteException e) { 3317 handleRemoteException(e); 3318 return false; 3319 } 3320 } 3321 } 3322 3323 // This creates a blob of IE elements from the array received. 3324 // TODO: This ugly conversion can be removed if we put IE elements in ScanResult. 3325 private static byte[] hidlIeArrayToFrameworkIeBlob(ArrayList<WifiInformationElement> ies) { 3326 if (ies == null || ies.isEmpty()) return new byte[0]; 3327 ArrayList<Byte> ieBlob = new ArrayList<>(); 3328 for (WifiInformationElement ie : ies) { 3329 ieBlob.add(ie.id); 3330 ieBlob.addAll(ie.data); 3331 } 3332 return NativeUtil.byteArrayFromArrayList(ieBlob); 3333 } 3334 3335 // This is only filling up the fields of Scan Result used by Gscan clients. 3336 private static ScanResult hidlToFrameworkScanResult(StaScanResult scanResult) { 3337 if (scanResult == null) return null; 3338 ScanResult frameworkScanResult = new ScanResult(); 3339 frameworkScanResult.SSID = NativeUtil.encodeSsid(scanResult.ssid); 3340 frameworkScanResult.wifiSsid = 3341 WifiSsid.createFromByteArray(NativeUtil.byteArrayFromArrayList(scanResult.ssid)); 3342 frameworkScanResult.BSSID = NativeUtil.macAddressFromByteArray(scanResult.bssid); 3343 frameworkScanResult.level = scanResult.rssi; 3344 frameworkScanResult.frequency = scanResult.frequency; 3345 frameworkScanResult.timestamp = scanResult.timeStampInUs; 3346 return frameworkScanResult; 3347 } 3348 3349 private static ScanResult[] hidlToFrameworkScanResults(ArrayList<StaScanResult> scanResults) { 3350 if (scanResults == null || scanResults.isEmpty()) return new ScanResult[0]; 3351 ScanResult[] frameworkScanResults = new ScanResult[scanResults.size()]; 3352 int i = 0; 3353 for (StaScanResult scanResult : scanResults) { 3354 frameworkScanResults[i++] = hidlToFrameworkScanResult(scanResult); 3355 } 3356 return frameworkScanResults; 3357 } 3358 3359 /** 3360 * This just returns whether the scan was interrupted or not. 3361 */ 3362 private static int hidlToFrameworkScanDataFlags(int flag) { 3363 if (flag == StaScanDataFlagMask.INTERRUPTED) { 3364 return 1; 3365 } else { 3366 return 0; 3367 } 3368 } 3369 3370 private static WifiScanner.ScanData[] hidlToFrameworkScanDatas( 3371 int cmdId, ArrayList<StaScanData> scanDatas) { 3372 if (scanDatas == null || scanDatas.isEmpty()) return new WifiScanner.ScanData[0]; 3373 WifiScanner.ScanData[] frameworkScanDatas = new WifiScanner.ScanData[scanDatas.size()]; 3374 int i = 0; 3375 for (StaScanData scanData : scanDatas) { 3376 int flags = hidlToFrameworkScanDataFlags(scanData.flags); 3377 ScanResult[] frameworkScanResults = hidlToFrameworkScanResults(scanData.results); 3378 frameworkScanDatas[i++] = 3379 new WifiScanner.ScanData(cmdId, flags, scanData.bucketsScanned, 3380 WifiScanner.WIFI_BAND_UNSPECIFIED, frameworkScanResults); 3381 } 3382 return frameworkScanDatas; 3383 } 3384 3385 /** 3386 * Callback for events on the STA interface. 3387 */ 3388 private class StaIfaceEventCallback extends IWifiStaIfaceEventCallback.Stub { 3389 @Override 3390 public void onBackgroundScanFailure(int cmdId) { 3391 mVerboseLog.d("onBackgroundScanFailure " + cmdId); 3392 WifiNative.ScanEventHandler eventHandler; 3393 synchronized (sLock) { 3394 if (mScan == null || cmdId != mScan.cmdId) return; 3395 eventHandler = mScan.eventHandler; 3396 } 3397 eventHandler.onScanStatus(WifiNative.WIFI_SCAN_FAILED); 3398 } 3399 3400 @Override 3401 public void onBackgroundFullScanResult( 3402 int cmdId, int bucketsScanned, StaScanResult result) { 3403 mVerboseLog.d("onBackgroundFullScanResult " + cmdId); 3404 WifiNative.ScanEventHandler eventHandler; 3405 synchronized (sLock) { 3406 if (mScan == null || cmdId != mScan.cmdId) return; 3407 eventHandler = mScan.eventHandler; 3408 } 3409 eventHandler.onFullScanResult(hidlToFrameworkScanResult(result), bucketsScanned); 3410 } 3411 3412 @Override 3413 public void onBackgroundScanResults(int cmdId, ArrayList<StaScanData> scanDatas) { 3414 mVerboseLog.d("onBackgroundScanResults " + cmdId); 3415 WifiNative.ScanEventHandler eventHandler; 3416 // WifiScanner currently uses the results callback to fetch the scan results. 3417 // So, simulate that by sending out the notification and then caching the results 3418 // locally. This will then be returned to WifiScanner via getScanResults. 3419 synchronized (sLock) { 3420 if (mScan == null || cmdId != mScan.cmdId) return; 3421 eventHandler = mScan.eventHandler; 3422 mScan.latestScanResults = hidlToFrameworkScanDatas(cmdId, scanDatas); 3423 } 3424 eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); 3425 } 3426 3427 @Override 3428 public void onRssiThresholdBreached(int cmdId, byte[/* 6 */] currBssid, int currRssi) { 3429 mVerboseLog.d("onRssiThresholdBreached " + cmdId + "currRssi " + currRssi); 3430 WifiNative.WifiRssiEventHandler eventHandler; 3431 synchronized (sLock) { 3432 if (mWifiRssiEventHandler == null || cmdId != sRssiMonCmdId) return; 3433 eventHandler = mWifiRssiEventHandler; 3434 } 3435 eventHandler.onRssiThresholdBreached((byte) currRssi); 3436 } 3437 } 3438 3439 /** 3440 * Callback for events on the chip. 3441 */ 3442 private class ChipEventCallback extends IWifiChipEventCallback.Stub { 3443 @Override 3444 public void onChipReconfigured(int modeId) { 3445 mVerboseLog.d("onChipReconfigured " + modeId); 3446 } 3447 3448 @Override 3449 public void onChipReconfigureFailure(WifiStatus status) { 3450 mVerboseLog.d("onChipReconfigureFailure " + status); 3451 } 3452 3453 public void onIfaceAdded(int type, String name) { 3454 mVerboseLog.d("onIfaceAdded " + type + ", name: " + name); 3455 } 3456 3457 @Override 3458 public void onIfaceRemoved(int type, String name) { 3459 mVerboseLog.d("onIfaceRemoved " + type + ", name: " + name); 3460 } 3461 3462 @Override 3463 public void onDebugRingBufferDataAvailable( 3464 WifiDebugRingBufferStatus status, java.util.ArrayList<Byte> data) { 3465 //TODO(b/35875078) Reinstate logging when execessive callbacks are fixed 3466 // mVerboseLog.d("onDebugRingBufferDataAvailable " + status); 3467 mHalEventHandler.post(() -> { 3468 WifiNative.WifiLoggerEventHandler eventHandler; 3469 synchronized (sLock) { 3470 if (mLogEventHandler == null || status == null || data == null) return; 3471 eventHandler = mLogEventHandler; 3472 } 3473 // Because |sLock| has been released, there is a chance that we'll execute 3474 // a spurious callback (after someone has called resetLogHandler()). 3475 // 3476 // However, the alternative risks deadlock. Consider: 3477 // [T1.1] WifiDiagnostics.captureBugReport() 3478 // [T1.2] -- acquire WifiDiagnostics object's intrinsic lock 3479 // [T1.3] -> WifiVendorHal.getRingBufferData() 3480 // [T1.4] -- acquire WifiVendorHal.sLock 3481 // [T2.1] <lambda>() 3482 // [T2.2] -- acquire WifiVendorHal.sLock 3483 // [T2.3] -> WifiDiagnostics.onRingBufferData() 3484 // [T2.4] -- acquire WifiDiagnostics object's intrinsic lock 3485 // 3486 // The problem here is that the two threads acquire the locks in opposite order. 3487 // If, for example, T2.2 executes between T1.2 and 1.4, then T1 and T2 3488 // will be deadlocked. 3489 int sizeBefore = data.size(); 3490 boolean conversionFailure = false; 3491 try { 3492 eventHandler.onRingBufferData( 3493 ringBufferStatus(status), NativeUtil.byteArrayFromArrayList(data)); 3494 int sizeAfter = data.size(); 3495 if (sizeAfter != sizeBefore) { 3496 conversionFailure = true; 3497 } 3498 } catch (ArrayIndexOutOfBoundsException e) { 3499 conversionFailure = true; 3500 } 3501 if (conversionFailure) { 3502 Log.wtf("WifiVendorHal", "Conversion failure detected in " 3503 + "onDebugRingBufferDataAvailable. " 3504 + "The input ArrayList |data| is potentially corrupted. " 3505 + "Starting size=" + sizeBefore + ", " 3506 + "final size=" + data.size()); 3507 } 3508 }); 3509 } 3510 3511 @Override 3512 public void onDebugErrorAlert(int errorCode, java.util.ArrayList<Byte> debugData) { 3513 mLog.w("onDebugErrorAlert " + errorCode); 3514 mHalEventHandler.post(() -> { 3515 WifiNative.WifiLoggerEventHandler eventHandler; 3516 synchronized (sLock) { 3517 if (mLogEventHandler == null || debugData == null) return; 3518 eventHandler = mLogEventHandler; 3519 } 3520 // See comment in onDebugRingBufferDataAvailable(), for an explanation 3521 // of why this callback is invoked without |sLock| held. 3522 eventHandler.onWifiAlert( 3523 errorCode, NativeUtil.byteArrayFromArrayList(debugData)); 3524 }); 3525 } 3526 } 3527 3528 private boolean areSameIfaceNames(List<IfaceInfo> ifaceList1, List<IfaceInfo> ifaceList2) { 3529 List<String> ifaceNamesList1 = ifaceList1 3530 .stream() 3531 .map(i -> i.name) 3532 .collect(Collectors.toList()); 3533 List<String> ifaceNamesList2 = ifaceList2 3534 .stream() 3535 .map(i -> i.name) 3536 .collect(Collectors.toList()); 3537 return ifaceNamesList1.containsAll(ifaceNamesList2); 3538 } 3539 3540 /** 3541 * Callback for events on the 1.2 chip. 3542 */ 3543 private class ChipEventCallbackV12 extends 3544 android.hardware.wifi.V1_2.IWifiChipEventCallback.Stub { 3545 @Override 3546 public void onChipReconfigured(int modeId) { 3547 mIWifiChipEventCallback.onChipReconfigured(modeId); 3548 } 3549 3550 @Override 3551 public void onChipReconfigureFailure(WifiStatus status) { 3552 mIWifiChipEventCallback.onChipReconfigureFailure(status); 3553 } 3554 3555 public void onIfaceAdded(int type, String name) { 3556 mIWifiChipEventCallback.onIfaceAdded(type, name); 3557 } 3558 3559 @Override 3560 public void onIfaceRemoved(int type, String name) { 3561 mIWifiChipEventCallback.onIfaceRemoved(type, name); 3562 } 3563 3564 @Override 3565 public void onDebugRingBufferDataAvailable( 3566 WifiDebugRingBufferStatus status, java.util.ArrayList<Byte> data) { 3567 mIWifiChipEventCallback.onDebugRingBufferDataAvailable(status, data); 3568 } 3569 3570 @Override 3571 public void onDebugErrorAlert(int errorCode, java.util.ArrayList<Byte> debugData) { 3572 mIWifiChipEventCallback.onDebugErrorAlert(errorCode, debugData); 3573 } 3574 3575 @Override 3576 public void onRadioModeChange(ArrayList<RadioModeInfo> radioModeInfoList) { 3577 mVerboseLog.d("onRadioModeChange " + radioModeInfoList); 3578 WifiNative.VendorHalRadioModeChangeEventHandler handler; 3579 synchronized (sLock) { 3580 if (mRadioModeChangeEventHandler == null || radioModeInfoList == null) return; 3581 handler = mRadioModeChangeEventHandler; 3582 } 3583 // Should only contain 1 or 2 radio infos. 3584 if (radioModeInfoList.size() == 0 || radioModeInfoList.size() > 2) { 3585 mLog.e("Unexpected number of radio info in list " + radioModeInfoList.size()); 3586 return; 3587 } 3588 RadioModeInfo radioModeInfo0 = radioModeInfoList.get(0); 3589 RadioModeInfo radioModeInfo1 = 3590 radioModeInfoList.size() == 2 ? radioModeInfoList.get(1) : null; 3591 // Number of ifaces on each radio should be equal. 3592 if (radioModeInfo1 != null 3593 && radioModeInfo0.ifaceInfos.size() != radioModeInfo1.ifaceInfos.size()) { 3594 mLog.e("Unexpected number of iface info in list " 3595 + radioModeInfo0.ifaceInfos.size() + ", " 3596 + radioModeInfo1.ifaceInfos.size()); 3597 return; 3598 } 3599 int numIfacesOnEachRadio = radioModeInfo0.ifaceInfos.size(); 3600 // Only 1 or 2 ifaces should be present on each radio. 3601 if (numIfacesOnEachRadio == 0 || numIfacesOnEachRadio > 2) { 3602 mLog.e("Unexpected number of iface info in list " + numIfacesOnEachRadio); 3603 return; 3604 } 3605 Runnable runnable = null; 3606 // 2 ifaces simultaneous on 2 radios. 3607 if (radioModeInfoList.size() == 2 && numIfacesOnEachRadio == 1) { 3608 // Iface on radio0 should be different from the iface on radio1 for DBS & SBS. 3609 if (areSameIfaceNames(radioModeInfo0.ifaceInfos, radioModeInfo1.ifaceInfos)) { 3610 mLog.e("Unexpected for both radio infos to have same iface"); 3611 return; 3612 } 3613 if (radioModeInfo0.bandInfo != radioModeInfo1.bandInfo) { 3614 runnable = () -> { 3615 handler.onDbs(); 3616 }; 3617 } else { 3618 runnable = () -> { 3619 handler.onSbs(radioModeInfo0.bandInfo); 3620 }; 3621 } 3622 // 2 ifaces time sharing on 1 radio. 3623 } else if (radioModeInfoList.size() == 1 && numIfacesOnEachRadio == 2) { 3624 IfaceInfo ifaceInfo0 = radioModeInfo0.ifaceInfos.get(0); 3625 IfaceInfo ifaceInfo1 = radioModeInfo0.ifaceInfos.get(1); 3626 if (ifaceInfo0.channel != ifaceInfo1.channel) { 3627 runnable = () -> { 3628 handler.onMcc(radioModeInfo0.bandInfo); 3629 }; 3630 } else { 3631 runnable = () -> { 3632 handler.onScc(radioModeInfo0.bandInfo); 3633 }; 3634 } 3635 } else { 3636 // Not concurrency scenario, uninteresting... 3637 } 3638 if (runnable != null) mHalEventHandler.post(runnable); 3639 } 3640 } 3641 3642 /** 3643 * Callback for events on the 1.4 chip. 3644 */ 3645 private class ChipEventCallbackV14 extends 3646 android.hardware.wifi.V1_4.IWifiChipEventCallback.Stub { 3647 @Override 3648 public void onChipReconfigured(int modeId) { 3649 mIWifiChipEventCallback.onChipReconfigured(modeId); 3650 } 3651 3652 @Override 3653 public void onChipReconfigureFailure(WifiStatus status) { 3654 mIWifiChipEventCallback.onChipReconfigureFailure(status); 3655 } 3656 3657 public void onIfaceAdded(int type, String name) { 3658 mIWifiChipEventCallback.onIfaceAdded(type, name); 3659 } 3660 3661 @Override 3662 public void onIfaceRemoved(int type, String name) { 3663 mIWifiChipEventCallback.onIfaceRemoved(type, name); 3664 } 3665 3666 @Override 3667 public void onDebugRingBufferDataAvailable( 3668 WifiDebugRingBufferStatus status, java.util.ArrayList<Byte> data) { 3669 mIWifiChipEventCallback.onDebugRingBufferDataAvailable(status, data); 3670 } 3671 3672 @Override 3673 public void onDebugErrorAlert(int errorCode, java.util.ArrayList<Byte> debugData) { 3674 mIWifiChipEventCallback.onDebugErrorAlert(errorCode, debugData); 3675 } 3676 3677 @Override 3678 public void onRadioModeChange( 3679 ArrayList<android.hardware.wifi.V1_2.IWifiChipEventCallback.RadioModeInfo> 3680 radioModeInfoList) { 3681 mIWifiChipEventCallbackV12.onRadioModeChange(radioModeInfoList); 3682 } 3683 3684 @Override 3685 public void onRadioModeChange_1_4(ArrayList<RadioModeInfo> radioModeInfoList) { 3686 mVerboseLog.d("onRadioModeChange_1_4 " + radioModeInfoList); 3687 WifiNative.VendorHalRadioModeChangeEventHandler handler; 3688 synchronized (sLock) { 3689 if (mRadioModeChangeEventHandler == null || radioModeInfoList == null) return; 3690 handler = mRadioModeChangeEventHandler; 3691 } 3692 // Should only contain 1 or 2 radio infos. 3693 if (radioModeInfoList.size() == 0 || radioModeInfoList.size() > 2) { 3694 mLog.e("Unexpected number of radio info in list " + radioModeInfoList.size()); 3695 return; 3696 } 3697 RadioModeInfo radioModeInfo0 = radioModeInfoList.get(0); 3698 RadioModeInfo radioModeInfo1 = 3699 radioModeInfoList.size() == 2 ? radioModeInfoList.get(1) : null; 3700 // Number of ifaces on each radio should be equal. 3701 if (radioModeInfo1 != null 3702 && radioModeInfo0.ifaceInfos.size() != radioModeInfo1.ifaceInfos.size()) { 3703 mLog.e("Unexpected number of iface info in list " 3704 + radioModeInfo0.ifaceInfos.size() + ", " 3705 + radioModeInfo1.ifaceInfos.size()); 3706 return; 3707 } 3708 int numIfacesOnEachRadio = radioModeInfo0.ifaceInfos.size(); 3709 // Only 1 or 2 ifaces should be present on each radio. 3710 if (numIfacesOnEachRadio == 0 || numIfacesOnEachRadio > 2) { 3711 mLog.e("Unexpected number of iface info in list " + numIfacesOnEachRadio); 3712 return; 3713 } 3714 Runnable runnable = null; 3715 // 2 ifaces simultaneous on 2 radios. 3716 if (radioModeInfoList.size() == 2 && numIfacesOnEachRadio == 1) { 3717 // Iface on radio0 should be different from the iface on radio1 for DBS & SBS. 3718 if (areSameIfaceNames(radioModeInfo0.ifaceInfos, radioModeInfo1.ifaceInfos)) { 3719 mLog.e("Unexpected for both radio infos to have same iface"); 3720 return; 3721 } 3722 if (radioModeInfo0.bandInfo != radioModeInfo1.bandInfo) { 3723 runnable = () -> { 3724 handler.onDbs(); 3725 }; 3726 } else { 3727 runnable = () -> { 3728 handler.onSbs(radioModeInfo0.bandInfo); 3729 }; 3730 } 3731 // 2 ifaces time sharing on 1 radio. 3732 } else if (radioModeInfoList.size() == 1 && numIfacesOnEachRadio == 2) { 3733 IfaceInfo ifaceInfo0 = radioModeInfo0.ifaceInfos.get(0); 3734 IfaceInfo ifaceInfo1 = radioModeInfo0.ifaceInfos.get(1); 3735 if (ifaceInfo0.channel != ifaceInfo1.channel) { 3736 runnable = () -> { 3737 handler.onMcc(radioModeInfo0.bandInfo); 3738 }; 3739 } else { 3740 runnable = () -> { 3741 handler.onScc(radioModeInfo0.bandInfo); 3742 }; 3743 } 3744 } else { 3745 // Not concurrency scenario, uninteresting... 3746 } 3747 if (runnable != null) mHalEventHandler.post(runnable); 3748 } 3749 } 3750 3751 /** 3752 * Hal Device Manager callbacks. 3753 */ 3754 public class HalDeviceManagerStatusListener implements HalDeviceManager.ManagerStatusListener { 3755 @Override 3756 public void onStatusChanged() { 3757 boolean isReady = mHalDeviceManager.isReady(); 3758 boolean isStarted = mHalDeviceManager.isStarted(); 3759 3760 mVerboseLog.i("Device Manager onStatusChanged. isReady(): " + isReady 3761 + ", isStarted(): " + isStarted); 3762 if (!isReady) { 3763 // Probably something unpleasant, e.g. the server died 3764 WifiNative.VendorHalDeathEventHandler handler; 3765 synchronized (sLock) { 3766 clearState(); 3767 handler = mDeathEventHandler; 3768 } 3769 if (handler != null) { 3770 handler.onDeath(); 3771 } 3772 } 3773 } 3774 } 3775 3776 /** 3777 * Trigger subsystem restart in vendor side 3778 */ 3779 public boolean startSubsystemRestart() { 3780 synchronized (sLock) { 3781 android.hardware.wifi.V1_5.IWifiChip iWifiChipV15 = getWifiChipForV1_5Mockable(); 3782 if (iWifiChipV15 != null) { 3783 try { 3784 return ok(iWifiChipV15.triggerSubsystemRestart()); 3785 } catch (RemoteException e) { 3786 handleRemoteException(e); 3787 return false; 3788 } 3789 } 3790 // HAL version does not support this api 3791 return false; 3792 } 3793 } 3794 3795 /** 3796 * Convert framework's operational mode to HAL's operational mode. 3797 */ 3798 private int frameworkToHalIfaceMode(@WifiAvailableChannel.OpMode int mode) { 3799 int halMode = 0; 3800 if ((mode & WifiAvailableChannel.OP_MODE_STA) != 0) { 3801 halMode |= WifiIfaceMode.IFACE_MODE_STA; 3802 } 3803 if ((mode & WifiAvailableChannel.OP_MODE_SAP) != 0) { 3804 halMode |= WifiIfaceMode.IFACE_MODE_SOFTAP; 3805 } 3806 if ((mode & WifiAvailableChannel.OP_MODE_WIFI_DIRECT_CLI) != 0) { 3807 halMode |= WifiIfaceMode.IFACE_MODE_P2P_CLIENT; 3808 } 3809 if ((mode & WifiAvailableChannel.OP_MODE_WIFI_DIRECT_GO) != 0) { 3810 halMode |= WifiIfaceMode.IFACE_MODE_P2P_GO; 3811 } 3812 if ((mode & WifiAvailableChannel.OP_MODE_WIFI_AWARE) != 0) { 3813 halMode |= WifiIfaceMode.IFACE_MODE_NAN; 3814 } 3815 if ((mode & WifiAvailableChannel.OP_MODE_TDLS) != 0) { 3816 halMode |= WifiIfaceMode.IFACE_MODE_TDLS; 3817 } 3818 return halMode; 3819 } 3820 3821 /** 3822 * Convert from HAL's operational mode to framework's operational mode. 3823 */ 3824 private @WifiAvailableChannel.OpMode int frameworkFromHalIfaceMode(int halMode) { 3825 int mode = 0; 3826 if ((halMode & WifiIfaceMode.IFACE_MODE_STA) != 0) { 3827 mode |= WifiAvailableChannel.OP_MODE_STA; 3828 } 3829 if ((halMode & WifiIfaceMode.IFACE_MODE_SOFTAP) != 0) { 3830 mode |= WifiAvailableChannel.OP_MODE_SAP; 3831 } 3832 if ((halMode & WifiIfaceMode.IFACE_MODE_P2P_CLIENT) != 0) { 3833 mode |= WifiAvailableChannel.OP_MODE_WIFI_DIRECT_CLI; 3834 } 3835 if ((halMode & WifiIfaceMode.IFACE_MODE_P2P_GO) != 0) { 3836 mode |= WifiAvailableChannel.OP_MODE_WIFI_DIRECT_GO; 3837 } 3838 if ((halMode & WifiIfaceMode.IFACE_MODE_NAN) != 0) { 3839 mode |= WifiAvailableChannel.OP_MODE_WIFI_AWARE; 3840 } 3841 if ((halMode & WifiIfaceMode.IFACE_MODE_TDLS) != 0) { 3842 mode |= WifiAvailableChannel.OP_MODE_TDLS; 3843 } 3844 return mode; 3845 } 3846 3847 /** 3848 * Convert framework's WifiAvailableChannel.FILTER_* to HAL's UsableChannelFilter. 3849 */ 3850 private int frameworkToHalUsableFilter(@WifiAvailableChannel.Filter int filter) { 3851 int halFilter = 0; // O implies no additional filter other than regulatory (default) 3852 3853 if ((filter & WifiAvailableChannel.FILTER_CONCURRENCY) != 0) { 3854 halFilter |= UsableChannelFilter.CONCURRENCY; 3855 } 3856 if ((filter & WifiAvailableChannel.FILTER_CELLULAR_COEXISTENCE) != 0) { 3857 halFilter |= UsableChannelFilter.CELLULAR_COEXISTENCE; 3858 } 3859 return halFilter; 3860 } 3861 3862 /** 3863 * Retrieve the list of usable Wifi channels. 3864 */ 3865 public List<WifiAvailableChannel> getUsableChannels( 3866 @WifiScanner.WifiBand int band, 3867 @WifiAvailableChannel.OpMode int mode, 3868 @WifiAvailableChannel.Filter int filter) { 3869 synchronized (sLock) { 3870 try { 3871 android.hardware.wifi.V1_5.IWifiChip iWifiChipV15 = getWifiChipForV1_5Mockable(); 3872 if (iWifiChipV15 == null) { 3873 return null; 3874 } 3875 Mutable<List<WifiAvailableChannel>> answer = new Mutable<>(); 3876 iWifiChipV15.getUsableChannels( 3877 makeWifiBandFromFrameworkBand(band), 3878 frameworkToHalIfaceMode(mode), 3879 frameworkToHalUsableFilter(filter), (status, channels) -> { 3880 if (!ok(status)) return; 3881 answer.value = new ArrayList<>(); 3882 for (WifiUsableChannel ch : channels) { 3883 answer.value.add(new WifiAvailableChannel(ch.channel, 3884 frameworkFromHalIfaceMode(ch.ifaceModeMask))); 3885 } 3886 }); 3887 return answer.value; 3888 } catch (RemoteException e) { 3889 handleRemoteException(e); 3890 return null; 3891 } catch (IllegalArgumentException e) { 3892 mLog.e("Illegal argument for getUsableChannels() " + e); 3893 return null; 3894 } 3895 } 3896 } 3897 } 3898