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