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