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