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