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