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 IWifiStaIface caps
    782      */
    783     private static final int[][] sFeatureCapabilityTranslation = {
    784             {WifiManager.WIFI_FEATURE_INFRA_5G,
    785                     IWifiStaIface.StaIfaceCapabilityMask.STA_5G
    786             },
    787             {WifiManager.WIFI_FEATURE_PASSPOINT,
    788                     IWifiStaIface.StaIfaceCapabilityMask.HOTSPOT
    789             },
    790             {WifiManager.WIFI_FEATURE_SCANNER,
    791                     IWifiStaIface.StaIfaceCapabilityMask.BACKGROUND_SCAN,
    792             },
    793             {WifiManager.WIFI_FEATURE_PNO,
    794                     IWifiStaIface.StaIfaceCapabilityMask.PNO
    795             },
    796             {WifiManager.WIFI_FEATURE_TDLS,
    797                     IWifiStaIface.StaIfaceCapabilityMask.TDLS
    798             },
    799             {WifiManager.WIFI_FEATURE_TDLS_OFFCHANNEL,
    800                     IWifiStaIface.StaIfaceCapabilityMask.TDLS_OFFCHANNEL
    801             },
    802             {WifiManager.WIFI_FEATURE_LINK_LAYER_STATS,
    803                     IWifiStaIface.StaIfaceCapabilityMask.LINK_LAYER_STATS
    804             },
    805             {WifiManager.WIFI_FEATURE_RSSI_MONITOR,
    806                     IWifiStaIface.StaIfaceCapabilityMask.RSSI_MONITOR
    807             },
    808             {WifiManager.WIFI_FEATURE_MKEEP_ALIVE,
    809                     IWifiStaIface.StaIfaceCapabilityMask.KEEP_ALIVE
    810             },
    811             {WifiManager.WIFI_FEATURE_CONFIG_NDO,
    812                     IWifiStaIface.StaIfaceCapabilityMask.ND_OFFLOAD
    813             },
    814             {WifiManager.WIFI_FEATURE_CONTROL_ROAMING,
    815                     IWifiStaIface.StaIfaceCapabilityMask.CONTROL_ROAMING
    816             },
    817             {WifiManager.WIFI_FEATURE_IE_WHITELIST,
    818                     IWifiStaIface.StaIfaceCapabilityMask.PROBE_IE_WHITELIST
    819             },
    820             {WifiManager.WIFI_FEATURE_SCAN_RAND,
    821                     IWifiStaIface.StaIfaceCapabilityMask.SCAN_RAND
    822             },
    823     };
    824 
    825     /**
    826      * Feature bit mask translation for STAs
    827      *
    828      * @param capabilities bitmask defined IWifiStaIface.StaIfaceCapabilityMask
    829      * @return bitmask defined by WifiManager.WIFI_FEATURE_*
    830      */
    831     @VisibleForTesting
    832     int wifiFeatureMaskFromStaCapabilities(int capabilities) {
    833         int features = 0;
    834         for (int i = 0; i < sFeatureCapabilityTranslation.length; i++) {
    835             if ((capabilities & sFeatureCapabilityTranslation[i][1]) != 0) {
    836                 features |= sFeatureCapabilityTranslation[i][0];
    837             }
    838         }
    839         return features;
    840     }
    841 
    842     /**
    843      * Get the supported features
    844      *
    845      * The result may differ depending on the mode (STA or AP)
    846      *
    847      * @return bitmask defined by WifiManager.WIFI_FEATURE_*
    848      */
    849     public int getSupportedFeatureSet() {
    850         int featureSet = 0;
    851         try {
    852             final MutableInt feat = new MutableInt(0);
    853             synchronized (sLock) {
    854                 if (mIWifiStaIface != null) {
    855                     mIWifiStaIface.getCapabilities((status, capabilities) -> {
    856                         if (!ok(status)) return;
    857                         feat.value = wifiFeatureMaskFromStaCapabilities(capabilities);
    858                     });
    859                 }
    860             }
    861             featureSet = feat.value;
    862         } catch (RemoteException e) {
    863             handleRemoteException(e);
    864             return 0;
    865         }
    866 
    867         Set<Integer> supportedIfaceTypes = mHalDeviceManager.getSupportedIfaceTypes();
    868         if (supportedIfaceTypes.contains(IfaceType.STA)) {
    869             featureSet |= WifiManager.WIFI_FEATURE_INFRA;
    870         }
    871         if (supportedIfaceTypes.contains(IfaceType.AP)) {
    872             featureSet |= WifiManager.WIFI_FEATURE_MOBILE_HOTSPOT;
    873         }
    874         if (supportedIfaceTypes.contains(IfaceType.P2P)) {
    875             featureSet |= WifiManager.WIFI_FEATURE_P2P;
    876         }
    877         if (supportedIfaceTypes.contains(IfaceType.NAN)) {
    878             featureSet |= WifiManager.WIFI_FEATURE_AWARE;
    879         }
    880 
    881         return featureSet;
    882     }
    883 
    884     /* RTT related commands/events */
    885 
    886     /**
    887      * RTT (Round Trip Time) measurement capabilities of the device.
    888      */
    889     public RttManager.RttCapabilities getRttCapabilities() {
    890         class AnswerBox {
    891             public RttManager.RttCapabilities value = null;
    892         }
    893         synchronized (sLock) {
    894             if (mIWifiRttController == null) return null;
    895             try {
    896                 AnswerBox box = new AnswerBox();
    897                 mIWifiRttController.getCapabilities((status, capabilities) -> {
    898                     if (!ok(status)) return;
    899                     mVerboseLog.info("rtt capabilites %").c(capabilities.toString()).flush();
    900                     RttManager.RttCapabilities ans = new RttManager.RttCapabilities();
    901                     ans.oneSidedRttSupported = capabilities.rttOneSidedSupported;
    902                     ans.twoSided11McRttSupported = capabilities.rttFtmSupported;
    903                     ans.lciSupported = capabilities.lciSupported;
    904                     ans.lcrSupported = capabilities.lcrSupported;
    905                     ans.preambleSupported = frameworkPreambleFromHalPreamble(
    906                             capabilities.preambleSupport);
    907                     ans.bwSupported = frameworkBwFromHalBw(capabilities.bwSupport);
    908                     ans.responderSupported = capabilities.responderSupported;
    909                     ans.secureRttSupported = false;
    910                     ans.mcVersion = ((int) capabilities.mcVersion) & 0xff;
    911                     box.value = ans;
    912                 });
    913                 return box.value;
    914             } catch (RemoteException e) {
    915                 handleRemoteException(e);
    916                 return null;
    917             }
    918         }
    919     }
    920 
    921     private int mRttCmdIdNext = 1;              // used to generate new command ids
    922     private int mRttCmdId;                      // id of currently active request
    923     // Event handler for current active RTT request.
    924     private WifiNative.RttEventHandler mRttEventHandler;
    925 
    926     /**
    927      * Receives a callback from the Hal and passes it along to our client using RttEventHandler
    928      */
    929     private class RttEventCallback extends IWifiRttControllerEventCallback.Stub {
    930 
    931         @Override
    932         public void onResults(int cmdId, java.util.ArrayList<RttResult> results) {
    933             WifiNative.RttEventHandler eventHandler;
    934             synchronized (sLock) {
    935                 if (cmdId != mRttCmdId || mRttEventHandler == null) return;
    936                 eventHandler = mRttEventHandler;
    937                 // Reset the command id for RTT operations in WifiVendorHal.
    938                 WifiVendorHal.this.mRttCmdId = 0;
    939             }
    940             RttManager.RttResult[] rtt = new RttManager.RttResult[results.size()];
    941             for (int i = 0; i < rtt.length; i++) {
    942                 rtt[i] = frameworkRttResultFromHalRttResult(results.get(i));
    943             }
    944             eventHandler.onRttResults(rtt);
    945         }
    946     }
    947 
    948     /**
    949      * Converts a Hal RttResult to a RttManager.RttResult
    950      */
    951     @VisibleForTesting
    952     static RttManager.RttResult frameworkRttResultFromHalRttResult(RttResult result) {
    953         RttManager.RttResult ans = new RttManager.RttResult();
    954         ans.bssid = NativeUtil.macAddressFromByteArray(result.addr);
    955         ans.burstNumber = result.burstNum;
    956         ans.measurementFrameNumber = result.measurementNumber;
    957         ans.successMeasurementFrameNumber = result.successNumber;
    958         ans.frameNumberPerBurstPeer = result.numberPerBurstPeer;
    959         ans.status = result.status; //TODO(b/35138520) - don't assume identity translation
    960         ans.retryAfterDuration = result.retryAfterDuration;
    961         ans.measurementType = result.type;
    962         ans.rssi = result.rssi;
    963         ans.rssiSpread = result.rssiSpread;
    964         //TODO(b/35138520) Fix HAL and framework to use the same units
    965         ans.txRate = result.txRate.bitRateInKbps;
    966         ans.rxRate = result.rxRate.bitRateInKbps;
    967         ans.rtt = result.rtt;
    968         ans.rttStandardDeviation = result.rttSd;
    969         ans.rttSpread = result.rttSpread;
    970         //TODO(b/35138520) These divide-by-10s were in the legacy Hal
    971         ans.distance = result.distanceInMm / 10; // Convert cm to mm
    972         ans.distanceStandardDeviation = result.distanceSdInMm / 10; // Convert cm to mm
    973         ans.distanceSpread = result.distanceSpreadInMm / 10;
    974 
    975         ans.ts = result.timeStampInUs;
    976         ans.burstDuration = result.burstDurationInMs;
    977         ans.negotiatedBurstNum = result.negotiatedBurstNum;
    978         ans.LCI = ieFromHal(result.lci);
    979         ans.LCR = ieFromHal(result.lcr);
    980         ans.secure = false; // Not present in HIDL HAL
    981         return ans;
    982     }
    983 
    984     /**
    985      * Convert a Hal WifiInformationElement to its RttManager equivalent
    986      */
    987     @VisibleForTesting
    988     static RttManager.WifiInformationElement ieFromHal(
    989             android.hardware.wifi.V1_0.WifiInformationElement ie) {
    990         if (ie == null) return null;
    991         RttManager.WifiInformationElement ans = new RttManager.WifiInformationElement();
    992         ans.id = ie.id;
    993         ans.data = NativeUtil.byteArrayFromArrayList(ie.data);
    994         return ans;
    995     }
    996 
    997     @VisibleForTesting
    998     static RttConfig halRttConfigFromFrameworkRttParams(RttManager.RttParams params) {
    999         RttConfig rttConfig = new RttConfig();
   1000         if (params.bssid != null) {
   1001             byte[] addr = NativeUtil.macAddressToByteArray(params.bssid);
   1002             for (int i = 0; i < rttConfig.addr.length; i++) {
   1003                 rttConfig.addr[i] = addr[i];
   1004             }
   1005         }
   1006         rttConfig.type = halRttTypeFromFrameworkRttType(params.requestType);
   1007         rttConfig.peer = halPeerFromFrameworkPeer(params.deviceType);
   1008         rttConfig.channel.width = halChannelWidthFromFrameworkChannelWidth(params.channelWidth);
   1009         rttConfig.channel.centerFreq = params.frequency;
   1010         rttConfig.channel.centerFreq0 = params.centerFreq0;
   1011         rttConfig.channel.centerFreq1 = params.centerFreq1;
   1012         rttConfig.burstPeriod = params.interval; // In 100ms units, 0 means no specific
   1013         rttConfig.numBurst = params.numberBurst;
   1014         rttConfig.numFramesPerBurst = params.numSamplesPerBurst;
   1015         rttConfig.numRetriesPerRttFrame = params.numRetriesPerMeasurementFrame;
   1016         rttConfig.numRetriesPerFtmr = params.numRetriesPerFTMR;
   1017         rttConfig.mustRequestLci = params.LCIRequest;
   1018         rttConfig.mustRequestLcr = params.LCRRequest;
   1019         rttConfig.burstDuration = params.burstTimeout;
   1020         rttConfig.preamble = halPreambleFromFrameworkPreamble(params.preamble);
   1021         rttConfig.bw = halBwFromFrameworkBw(params.bandwidth);
   1022         return rttConfig;
   1023     }
   1024 
   1025     @VisibleForTesting
   1026     static int halRttTypeFromFrameworkRttType(int frameworkRttType) {
   1027         switch (frameworkRttType) {
   1028             case RttManager.RTT_TYPE_ONE_SIDED:
   1029                 return RttType.ONE_SIDED;
   1030             case RttManager.RTT_TYPE_TWO_SIDED:
   1031                 return RttType.TWO_SIDED;
   1032             default:
   1033                 throw new IllegalArgumentException("bad " + frameworkRttType);
   1034         }
   1035     }
   1036 
   1037     @VisibleForTesting
   1038     static int frameworkRttTypeFromHalRttType(int halType) {
   1039         switch (halType) {
   1040             case RttType.ONE_SIDED:
   1041                 return RttManager.RTT_TYPE_ONE_SIDED;
   1042             case RttType.TWO_SIDED:
   1043                 return RttManager.RTT_TYPE_TWO_SIDED;
   1044             default:
   1045                 throw new IllegalArgumentException("bad " + halType);
   1046         }
   1047     }
   1048 
   1049     @VisibleForTesting
   1050     static int halPeerFromFrameworkPeer(int frameworkPeer) {
   1051         switch (frameworkPeer) {
   1052             case RttManager.RTT_PEER_TYPE_AP:
   1053                 return RttPeerType.AP;
   1054             case RttManager.RTT_PEER_TYPE_STA:
   1055                 return RttPeerType.STA;
   1056             case RttManager.RTT_PEER_P2P_GO:
   1057                 return RttPeerType.P2P_GO;
   1058             case RttManager.RTT_PEER_P2P_CLIENT:
   1059                 return RttPeerType.P2P_CLIENT;
   1060             case RttManager.RTT_PEER_NAN:
   1061                 return RttPeerType.NAN;
   1062             default:
   1063                 throw new IllegalArgumentException("bad " + frameworkPeer);
   1064         }
   1065     }
   1066 
   1067     @VisibleForTesting
   1068     static int frameworkPeerFromHalPeer(int halPeer) {
   1069         switch (halPeer) {
   1070             case RttPeerType.AP:
   1071                 return RttManager.RTT_PEER_TYPE_AP;
   1072             case RttPeerType.STA:
   1073                 return RttManager.RTT_PEER_TYPE_STA;
   1074             case RttPeerType.P2P_GO:
   1075                 return RttManager.RTT_PEER_P2P_GO;
   1076             case RttPeerType.P2P_CLIENT:
   1077                 return RttManager.RTT_PEER_P2P_CLIENT;
   1078             case RttPeerType.NAN:
   1079                 return RttManager.RTT_PEER_NAN;
   1080             default:
   1081                 throw new IllegalArgumentException("bad " + halPeer);
   1082 
   1083         }
   1084     }
   1085 
   1086     @VisibleForTesting
   1087     static int halChannelWidthFromFrameworkChannelWidth(int frameworkChannelWidth) {
   1088         switch (frameworkChannelWidth) {
   1089             case ScanResult.CHANNEL_WIDTH_20MHZ:
   1090                 return WifiChannelWidthInMhz.WIDTH_20;
   1091             case ScanResult.CHANNEL_WIDTH_40MHZ:
   1092                 return WifiChannelWidthInMhz.WIDTH_40;
   1093             case ScanResult.CHANNEL_WIDTH_80MHZ:
   1094                 return WifiChannelWidthInMhz.WIDTH_80;
   1095             case ScanResult.CHANNEL_WIDTH_160MHZ:
   1096                 return WifiChannelWidthInMhz.WIDTH_160;
   1097             case ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ:
   1098                 return WifiChannelWidthInMhz.WIDTH_80P80;
   1099             default:
   1100                 throw new IllegalArgumentException("bad " + frameworkChannelWidth);
   1101         }
   1102     }
   1103 
   1104     @VisibleForTesting
   1105     static int frameworkChannelWidthFromHalChannelWidth(int halChannelWidth) {
   1106         switch (halChannelWidth) {
   1107             case WifiChannelWidthInMhz.WIDTH_20:
   1108                 return ScanResult.CHANNEL_WIDTH_20MHZ;
   1109             case WifiChannelWidthInMhz.WIDTH_40:
   1110                 return ScanResult.CHANNEL_WIDTH_40MHZ;
   1111             case WifiChannelWidthInMhz.WIDTH_80:
   1112                 return ScanResult.CHANNEL_WIDTH_80MHZ;
   1113             case WifiChannelWidthInMhz.WIDTH_160:
   1114                 return ScanResult.CHANNEL_WIDTH_160MHZ;
   1115             case WifiChannelWidthInMhz.WIDTH_80P80:
   1116                 return ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ;
   1117             default:
   1118                 throw new IllegalArgumentException("bad " + halChannelWidth);
   1119         }
   1120     }
   1121 
   1122     @VisibleForTesting
   1123     static int halPreambleFromFrameworkPreamble(int rttManagerPreamble) {
   1124         BitMask checkoff = new BitMask(rttManagerPreamble);
   1125         int flags = 0;
   1126         if (checkoff.testAndClear(RttManager.PREAMBLE_LEGACY)) {
   1127             flags |= RttPreamble.LEGACY;
   1128         }
   1129         if (checkoff.testAndClear(RttManager.PREAMBLE_HT)) {
   1130             flags |= RttPreamble.HT;
   1131         }
   1132         if (checkoff.testAndClear(RttManager.PREAMBLE_VHT)) {
   1133             flags |= RttPreamble.VHT;
   1134         }
   1135         if (checkoff.value != 0) {
   1136             throw new IllegalArgumentException("bad " + rttManagerPreamble);
   1137         }
   1138         return flags;
   1139     }
   1140 
   1141     @VisibleForTesting
   1142     static int frameworkPreambleFromHalPreamble(int halPreamble) {
   1143         BitMask checkoff = new BitMask(halPreamble);
   1144         int flags = 0;
   1145         if (checkoff.testAndClear(RttPreamble.LEGACY)) {
   1146             flags |= RttManager.PREAMBLE_LEGACY;
   1147         }
   1148         if (checkoff.testAndClear(RttPreamble.HT)) {
   1149             flags |= RttManager.PREAMBLE_HT;
   1150         }
   1151         if (checkoff.testAndClear(RttPreamble.VHT)) {
   1152             flags |= RttManager.PREAMBLE_VHT;
   1153         }
   1154         if (checkoff.value != 0) {
   1155             throw new IllegalArgumentException("bad " + halPreamble);
   1156         }
   1157         return flags;
   1158     }
   1159 
   1160     @VisibleForTesting
   1161     static int halBwFromFrameworkBw(int rttManagerBandwidth) {
   1162         BitMask checkoff = new BitMask(rttManagerBandwidth);
   1163         int flags = 0;
   1164         if (checkoff.testAndClear(RttManager.RTT_BW_5_SUPPORT)) {
   1165             flags |= RttBw.BW_5MHZ;
   1166         }
   1167         if (checkoff.testAndClear(RttManager.RTT_BW_10_SUPPORT)) {
   1168             flags |= RttBw.BW_10MHZ;
   1169         }
   1170         if (checkoff.testAndClear(RttManager.RTT_BW_20_SUPPORT)) {
   1171             flags |= RttBw.BW_20MHZ;
   1172         }
   1173         if (checkoff.testAndClear(RttManager.RTT_BW_40_SUPPORT)) {
   1174             flags |= RttBw.BW_40MHZ;
   1175         }
   1176         if (checkoff.testAndClear(RttManager.RTT_BW_80_SUPPORT)) {
   1177             flags |= RttBw.BW_80MHZ;
   1178         }
   1179         if (checkoff.testAndClear(RttManager.RTT_BW_160_SUPPORT)) {
   1180             flags |= RttBw.BW_160MHZ;
   1181         }
   1182         if (checkoff.value != 0) {
   1183             throw new IllegalArgumentException("bad " + rttManagerBandwidth);
   1184         }
   1185         return flags;
   1186     }
   1187 
   1188     @VisibleForTesting
   1189     static int frameworkBwFromHalBw(int rttBw) {
   1190         BitMask checkoff = new BitMask(rttBw);
   1191         int flags = 0;
   1192         if (checkoff.testAndClear(RttBw.BW_5MHZ)) {
   1193             flags |= RttManager.RTT_BW_5_SUPPORT;
   1194         }
   1195         if (checkoff.testAndClear(RttBw.BW_10MHZ)) {
   1196             flags |= RttManager.RTT_BW_10_SUPPORT;
   1197         }
   1198         if (checkoff.testAndClear(RttBw.BW_20MHZ)) {
   1199             flags |= RttManager.RTT_BW_20_SUPPORT;
   1200         }
   1201         if (checkoff.testAndClear(RttBw.BW_40MHZ)) {
   1202             flags |= RttManager.RTT_BW_40_SUPPORT;
   1203         }
   1204         if (checkoff.testAndClear(RttBw.BW_80MHZ)) {
   1205             flags |= RttManager.RTT_BW_80_SUPPORT;
   1206         }
   1207         if (checkoff.testAndClear(RttBw.BW_160MHZ)) {
   1208             flags |= RttManager.RTT_BW_160_SUPPORT;
   1209         }
   1210         if (checkoff.value != 0) {
   1211             throw new IllegalArgumentException("bad " + rttBw);
   1212         }
   1213         return flags;
   1214     }
   1215 
   1216     @VisibleForTesting
   1217     static ArrayList<RttConfig> halRttConfigArrayFromFrameworkRttParamsArray(
   1218             RttManager.RttParams[] params) {
   1219         final int length = params.length;
   1220         ArrayList<RttConfig> configs = new ArrayList<RttConfig>(length);
   1221         for (int i = 0; i < length; i++) {
   1222             RttConfig config = halRttConfigFromFrameworkRttParams(params[i]);
   1223             if (config != null) {
   1224                 configs.add(config);
   1225             }
   1226         }
   1227         return configs;
   1228     }
   1229 
   1230     /**
   1231      * Starts a new rtt request
   1232      *
   1233      * @param params
   1234      * @param handler
   1235      * @return success indication
   1236      */
   1237     public boolean requestRtt(RttManager.RttParams[] params, WifiNative.RttEventHandler handler) {
   1238         ArrayList<RttConfig> rttConfigs;
   1239         try {
   1240             rttConfigs = halRttConfigArrayFromFrameworkRttParamsArray(params);
   1241         } catch (IllegalArgumentException e) {
   1242             mLog.err("Illegal argument for RTT request").c(e.toString()).flush();
   1243             return false;
   1244         }
   1245         synchronized (sLock) {
   1246             if (mIWifiRttController == null) return boolResult(false);
   1247             if (mRttCmdId != 0) return boolResult(false);
   1248             mRttCmdId = mRttCmdIdNext++;
   1249             mRttEventHandler = handler;
   1250             if (mRttCmdIdNext <= 0) mRttCmdIdNext = 1;
   1251             try {
   1252                 WifiStatus status = mIWifiRttController.rangeRequest(mRttCmdId, rttConfigs);
   1253                 if (ok(status)) return true;
   1254                 mRttCmdId = 0;
   1255                 return false;
   1256             } catch (RemoteException e) {
   1257                 handleRemoteException(e);
   1258                 return false;
   1259             }
   1260         }
   1261     }
   1262 
   1263     /**
   1264      * Cancels an outstanding rtt request
   1265      *
   1266      * @param params
   1267      * @return true if there was an outstanding request and it was successfully cancelled
   1268      */
   1269     public boolean cancelRtt(RttManager.RttParams[] params) {
   1270         ArrayList<RttConfig> rttConfigs = halRttConfigArrayFromFrameworkRttParamsArray(params);
   1271         synchronized (sLock) {
   1272             if (mIWifiRttController == null) return boolResult(false);
   1273             if (mRttCmdId == 0) return boolResult(false);
   1274             ArrayList<byte[/* 6 */]> addrs = new ArrayList<byte[]>(rttConfigs.size());
   1275             for (RttConfig x : rttConfigs) addrs.add(x.addr);
   1276             try {
   1277                 WifiStatus status = mIWifiRttController.rangeCancel(mRttCmdId, addrs);
   1278                 mRttCmdId = 0;
   1279                 if (!ok(status)) return false;
   1280                 return true;
   1281             } catch (RemoteException e) {
   1282                 handleRemoteException(e);
   1283                 return false;
   1284             }
   1285         }
   1286     }
   1287 
   1288     private int mRttResponderCmdId = 0;
   1289 
   1290     /**
   1291      * Get RTT responder information e.g. WiFi channel to enable responder on.
   1292      *
   1293      * @return info Instance of |RttResponder|, or null for error.
   1294      */
   1295     private RttResponder getRttResponder() {
   1296         class AnswerBox {
   1297             public RttResponder value = null;
   1298         }
   1299         synchronized (sLock) {
   1300             if (mIWifiRttController == null) return null;
   1301             AnswerBox answer = new AnswerBox();
   1302             try {
   1303                 mIWifiRttController.getResponderInfo((status, info) -> {
   1304                     if (!ok(status)) return;
   1305                     answer.value = info;
   1306                 });
   1307                 return answer.value;
   1308             } catch (RemoteException e) {
   1309                 handleRemoteException(e);
   1310                 return null;
   1311             }
   1312         }
   1313     }
   1314 
   1315     /**
   1316      * Convert Hal RttResponder to a framework ResponderConfig
   1317      *
   1318      * @param info Instance of |RttResponder|
   1319      * @return framework version of same
   1320      */
   1321     private ResponderConfig frameworkResponderConfigFromHalRttResponder(RttResponder info) {
   1322         ResponderConfig config = new ResponderConfig();
   1323         config.frequency = info.channel.centerFreq;
   1324         config.centerFreq0 = info.channel.centerFreq0;
   1325         config.centerFreq1 = info.channel.centerFreq1;
   1326         config.channelWidth = frameworkChannelWidthFromHalChannelWidth(info.channel.width);
   1327         config.preamble = frameworkPreambleFromHalPreamble(info.preamble);
   1328         return config;
   1329     }
   1330 
   1331     /**
   1332      * Enables RTT responder role on the device.
   1333      *
   1334      * @return {@link ResponderConfig} if the responder role is successfully enabled,
   1335      * {@code null} otherwise.
   1336      */
   1337     public ResponderConfig enableRttResponder(int timeoutSeconds) {
   1338         RttResponder info = getRttResponder();
   1339         synchronized (sLock) {
   1340             if (mIWifiRttController == null) return null;
   1341             if (mRttResponderCmdId != 0) {
   1342                 mLog.e("responder mode already enabled - this shouldn't happen");
   1343                 return null;
   1344             }
   1345             ResponderConfig config = null;
   1346             int id = mRttCmdIdNext++;
   1347             if (mRttCmdIdNext <= 0) mRttCmdIdNext = 1;
   1348             try {
   1349                 WifiStatus status = mIWifiRttController.enableResponder(
   1350                         /* cmdId */id,
   1351                         /* WifiChannelInfo channelHint */null,
   1352                         timeoutSeconds, info);
   1353                 if (ok(status)) {
   1354                     mRttResponderCmdId = id;
   1355                     config = frameworkResponderConfigFromHalRttResponder(info);
   1356                     mVerboseLog.i("enabling rtt " + mRttResponderCmdId);
   1357                 }
   1358                 return config;
   1359             } catch (RemoteException e) {
   1360                 handleRemoteException(e);
   1361                 return null;
   1362             }
   1363         }
   1364     }
   1365 
   1366     /**
   1367      * Disables RTT responder role.
   1368      *
   1369      * @return {@code true} if responder role is successfully disabled,
   1370      * {@code false} otherwise.
   1371      */
   1372     public boolean disableRttResponder() {
   1373         synchronized (sLock) {
   1374             if (mIWifiRttController == null) return boolResult(false);
   1375             if (mRttResponderCmdId == 0) return boolResult(false);
   1376             try {
   1377                 WifiStatus status = mIWifiRttController.disableResponder(mRttResponderCmdId);
   1378                 mRttResponderCmdId = 0;
   1379                 if (!ok(status)) return false;
   1380                 return true;
   1381             } catch (RemoteException e) {
   1382                 handleRemoteException(e);
   1383                 return false;
   1384             }
   1385         }
   1386     }
   1387 
   1388     /**
   1389      * Set the MAC OUI during scanning.
   1390      * <p>
   1391      * An OUI {Organizationally Unique Identifier} is a 24-bit number that
   1392      * uniquely identifies a vendor or manufacturer.
   1393      *
   1394      * @param oui
   1395      * @return true for success
   1396      */
   1397     public boolean setScanningMacOui(byte[] oui) {
   1398         if (oui == null) return boolResult(false);
   1399         if (oui.length != 3) return boolResult(false);
   1400         synchronized (sLock) {
   1401             try {
   1402                 if (mIWifiStaIface == null) return boolResult(false);
   1403                 WifiStatus status = mIWifiStaIface.setScanningMacOui(oui);
   1404                 if (!ok(status)) return false;
   1405                 return true;
   1406             } catch (RemoteException e) {
   1407                 handleRemoteException(e);
   1408                 return false;
   1409             }
   1410         }
   1411     }
   1412 
   1413     /**
   1414      * Query the list of valid frequencies for the provided band.
   1415      * <p>
   1416      * The result depends on the on the country code that has been set.
   1417      *
   1418      * @param band as specified by one of the WifiScanner.WIFI_BAND_* constants.
   1419      * @return frequencies vector of valid frequencies (MHz), or null for error.
   1420      * @throws IllegalArgumentException if band is not recognized.
   1421      */
   1422     public int[] getChannelsForBand(int band) {
   1423         enter("%").c(band).flush();
   1424         class AnswerBox {
   1425             public int[] value = null;
   1426         }
   1427         synchronized (sLock) {
   1428             try {
   1429                 AnswerBox box = new AnswerBox();
   1430                 int hb = makeWifiBandFromFrameworkBand(band);
   1431                 if (mIWifiStaIface != null) {
   1432                     mIWifiStaIface.getValidFrequenciesForBand(hb, (status, frequencies) -> {
   1433                         if (status.code == WifiStatusCode.ERROR_NOT_SUPPORTED) {
   1434                             mChannelsForBandSupport = false;
   1435                         }
   1436                         if (!ok(status)) return;
   1437                         mChannelsForBandSupport = true;
   1438                         box.value = intArrayFromArrayList(frequencies);
   1439                     });
   1440                 } else if (mIWifiApIface != null) {
   1441                     mIWifiApIface.getValidFrequenciesForBand(hb, (status, frequencies) -> {
   1442                         if (status.code == WifiStatusCode.ERROR_NOT_SUPPORTED) {
   1443                             mChannelsForBandSupport = false;
   1444                         }
   1445                         if (!ok(status)) return;
   1446                         mChannelsForBandSupport = true;
   1447                         box.value = intArrayFromArrayList(frequencies);
   1448                     });
   1449                 }
   1450                 return box.value;
   1451             } catch (RemoteException e) {
   1452                 handleRemoteException(e);
   1453                 return null;
   1454             }
   1455         }
   1456     }
   1457 
   1458     private int[] intArrayFromArrayList(ArrayList<Integer> in) {
   1459         int[] ans = new int[in.size()];
   1460         int i = 0;
   1461         for (Integer e : in) ans[i++] = e;
   1462         return ans;
   1463     }
   1464 
   1465     /**
   1466      * This holder is null until we know whether or not there is frequency-for-band support.
   1467      * <p>
   1468      * Set as a side-effect of getChannelsForBand.
   1469      */
   1470     @VisibleForTesting
   1471     Boolean mChannelsForBandSupport = null;
   1472 
   1473     /**
   1474      * Indicates whether getChannelsForBand is supported.
   1475      *
   1476      * @return true if it is.
   1477      */
   1478     public boolean isGetChannelsForBandSupported() {
   1479         if (mChannelsForBandSupport != null) return mChannelsForBandSupport;
   1480         getChannelsForBand(WifiBand.BAND_24GHZ);
   1481         if (mChannelsForBandSupport != null) return mChannelsForBandSupport;
   1482         return false;
   1483     }
   1484 
   1485     /**
   1486      * Get the APF (Android Packet Filter) capabilities of the device
   1487      */
   1488     public ApfCapabilities getApfCapabilities() {
   1489         class AnswerBox {
   1490             public ApfCapabilities value = sNoApfCapabilities;
   1491         }
   1492         synchronized (sLock) {
   1493             try {
   1494                 if (mIWifiStaIface == null) return sNoApfCapabilities;
   1495                 AnswerBox box = new AnswerBox();
   1496                 mIWifiStaIface.getApfPacketFilterCapabilities((status, capabilities) -> {
   1497                     if (!ok(status)) return;
   1498                     box.value = new ApfCapabilities(
   1499                         /* apfVersionSupported */   capabilities.version,
   1500                         /* maximumApfProgramSize */ capabilities.maxLength,
   1501                         /* apfPacketFormat */       android.system.OsConstants.ARPHRD_ETHER);
   1502                 });
   1503                 return box.value;
   1504             } catch (RemoteException e) {
   1505                 handleRemoteException(e);
   1506                 return sNoApfCapabilities;
   1507             }
   1508         }
   1509     }
   1510 
   1511     private static final ApfCapabilities sNoApfCapabilities = new ApfCapabilities(0, 0, 0);
   1512 
   1513     /**
   1514      * Installs an APF program on this iface, replacing any existing program.
   1515      *
   1516      * @param filter is the android packet filter program
   1517      * @return true for success
   1518      */
   1519     public boolean installPacketFilter(byte[] filter) {
   1520         int cmdId = 0; // We only aspire to support one program at a time
   1521         if (filter == null) return boolResult(false);
   1522         // Copy the program before taking the lock.
   1523         ArrayList<Byte> program = NativeUtil.byteArrayToArrayList(filter);
   1524         enter("filter length %").c(filter.length).flush();
   1525         synchronized (sLock) {
   1526             try {
   1527                 if (mIWifiStaIface == null) return boolResult(false);
   1528                 WifiStatus status = mIWifiStaIface.installApfPacketFilter(cmdId, program);
   1529                 if (!ok(status)) return false;
   1530                 return true;
   1531             } catch (RemoteException e) {
   1532                 handleRemoteException(e);
   1533                 return false;
   1534             }
   1535         }
   1536     }
   1537 
   1538     /**
   1539      * Set country code for this AP iface.
   1540      *
   1541      * @param countryCode - two-letter country code (as ISO 3166)
   1542      * @return true for success
   1543      */
   1544     public boolean setCountryCodeHal(String countryCode) {
   1545         if (countryCode == null) return boolResult(false);
   1546         if (countryCode.length() != 2) return boolResult(false);
   1547         byte[] code;
   1548         try {
   1549             code = NativeUtil.stringToByteArray(countryCode);
   1550         } catch (IllegalArgumentException e) {
   1551             return boolResult(false);
   1552         }
   1553         synchronized (sLock) {
   1554             try {
   1555                 if (mIWifiApIface == null) return boolResult(false);
   1556                 WifiStatus status = mIWifiApIface.setCountryCode(code);
   1557                 if (!ok(status)) return false;
   1558                 return true;
   1559             } catch (RemoteException e) {
   1560                 handleRemoteException(e);
   1561                 return false;
   1562             }
   1563         }
   1564     }
   1565 
   1566     private WifiNative.WifiLoggerEventHandler mLogEventHandler = null;
   1567 
   1568     /**
   1569      * Registers the logger callback and enables alerts.
   1570      * Ring buffer data collection is only triggered when |startLoggingRingBuffer| is invoked.
   1571      */
   1572     public boolean setLoggingEventHandler(WifiNative.WifiLoggerEventHandler handler) {
   1573         if (handler == null) return boolResult(false);
   1574         synchronized (sLock) {
   1575             if (mIWifiChip == null) return boolResult(false);
   1576             if (mLogEventHandler != null) return boolResult(false);
   1577             try {
   1578                 WifiStatus status = mIWifiChip.enableDebugErrorAlerts(true);
   1579                 if (!ok(status)) return false;
   1580                 mLogEventHandler = handler;
   1581                 return true;
   1582             } catch (RemoteException e) {
   1583                 handleRemoteException(e);
   1584                 return false;
   1585             }
   1586         }
   1587     }
   1588 
   1589     /**
   1590      * Stops all logging and resets the logger callback.
   1591      * This stops both the alerts and ring buffer data collection.
   1592      */
   1593     public boolean resetLogHandler() {
   1594         synchronized (sLock) {
   1595             if (mIWifiChip == null) return boolResult(false);
   1596             if (mLogEventHandler == null) return boolResult(false);
   1597             try {
   1598                 WifiStatus status = mIWifiChip.enableDebugErrorAlerts(false);
   1599                 if (!ok(status)) return false;
   1600                 status = mIWifiChip.stopLoggingToDebugRingBuffer();
   1601                 if (!ok(status)) return false;
   1602                 mLogEventHandler = null;
   1603                 return true;
   1604             } catch (RemoteException e) {
   1605                 handleRemoteException(e);
   1606                 return false;
   1607             }
   1608         }
   1609     }
   1610 
   1611     /**
   1612      * Control debug data collection
   1613      *
   1614      * @param verboseLevel       0 to 3, inclusive. 0 stops logging.
   1615      * @param flags              Ignored.
   1616      * @param maxIntervalInSec   Maximum interval between reports; ignore if 0.
   1617      * @param minDataSizeInBytes Minimum data size in buffer for report; ignore if 0.
   1618      * @param ringName           Name of the ring for which data collection is to start.
   1619      * @return true for success
   1620      */
   1621     public boolean startLoggingRingBuffer(int verboseLevel, int flags, int maxIntervalInSec,
   1622                                           int minDataSizeInBytes, String ringName) {
   1623         enter("verboseLevel=%, flags=%, maxIntervalInSec=%, minDataSizeInBytes=%, ringName=%")
   1624                 .c(verboseLevel).c(flags).c(maxIntervalInSec).c(minDataSizeInBytes).c(ringName)
   1625                 .flush();
   1626         synchronized (sLock) {
   1627             if (mIWifiChip == null) return boolResult(false);
   1628             try {
   1629                 // note - flags are not used
   1630                 WifiStatus status = mIWifiChip.startLoggingToDebugRingBuffer(
   1631                         ringName,
   1632                         verboseLevel,
   1633                         maxIntervalInSec,
   1634                         minDataSizeInBytes
   1635                 );
   1636                 return ok(status);
   1637             } catch (RemoteException e) {
   1638                 handleRemoteException(e);
   1639                 return false;
   1640             }
   1641         }
   1642     }
   1643 
   1644     /**
   1645      * Pointlessly fail
   1646      *
   1647      * @return -1
   1648      */
   1649     public int getSupportedLoggerFeatureSet() {
   1650         return -1;
   1651     }
   1652 
   1653     private String mDriverDescription; // Cached value filled by requestChipDebugInfo()
   1654 
   1655     /**
   1656      * Vendor-provided wifi driver version string
   1657      */
   1658     public String getDriverVersion() {
   1659         synchronized (sLock) {
   1660             if (mDriverDescription == null) requestChipDebugInfo();
   1661             return mDriverDescription;
   1662         }
   1663     }
   1664 
   1665     private String mFirmwareDescription; // Cached value filled by requestChipDebugInfo()
   1666 
   1667     /**
   1668      * Vendor-provided wifi firmware version string
   1669      */
   1670     public String getFirmwareVersion() {
   1671         synchronized (sLock) {
   1672             if (mFirmwareDescription == null) requestChipDebugInfo();
   1673             return mFirmwareDescription;
   1674         }
   1675     }
   1676 
   1677     /**
   1678      * Refreshes our idea of the driver and firmware versions
   1679      */
   1680     private void requestChipDebugInfo() {
   1681         mDriverDescription = null;
   1682         mFirmwareDescription = null;
   1683         try {
   1684             if (mIWifiChip == null) return;
   1685             mIWifiChip.requestChipDebugInfo((status, chipDebugInfo) -> {
   1686                 if (!ok(status)) return;
   1687                 mDriverDescription = chipDebugInfo.driverDescription;
   1688                 mFirmwareDescription = chipDebugInfo.firmwareDescription;
   1689             });
   1690         } catch (RemoteException e) {
   1691             handleRemoteException(e);
   1692             return;
   1693         }
   1694         mLog.info("Driver: % Firmware: %")
   1695                 .c(mDriverDescription)
   1696                 .c(mFirmwareDescription)
   1697                 .flush();
   1698     }
   1699 
   1700     /**
   1701      * Creates RingBufferStatus from the Hal version
   1702      */
   1703     private static WifiNative.RingBufferStatus ringBufferStatus(WifiDebugRingBufferStatus h) {
   1704         WifiNative.RingBufferStatus ans = new WifiNative.RingBufferStatus();
   1705         ans.name = h.ringName;
   1706         ans.flag = frameworkRingBufferFlagsFromHal(h.flags);
   1707         ans.ringBufferId = h.ringId;
   1708         ans.ringBufferByteSize = h.sizeInBytes;
   1709         ans.verboseLevel = h.verboseLevel;
   1710         // Remaining fields are unavailable
   1711         //  writtenBytes;
   1712         //  readBytes;
   1713         //  writtenRecords;
   1714         return ans;
   1715     }
   1716 
   1717     /**
   1718      * Translates a hal wifiDebugRingBufferFlag to the WifiNative version
   1719      */
   1720     private static int frameworkRingBufferFlagsFromHal(int wifiDebugRingBufferFlag) {
   1721         BitMask checkoff = new BitMask(wifiDebugRingBufferFlag);
   1722         int flags = 0;
   1723         if (checkoff.testAndClear(WifiDebugRingBufferFlags.HAS_BINARY_ENTRIES)) {
   1724             flags |= WifiNative.RingBufferStatus.HAS_BINARY_ENTRIES;
   1725         }
   1726         if (checkoff.testAndClear(WifiDebugRingBufferFlags.HAS_ASCII_ENTRIES)) {
   1727             flags |= WifiNative.RingBufferStatus.HAS_ASCII_ENTRIES;
   1728         }
   1729         if (checkoff.testAndClear(WifiDebugRingBufferFlags.HAS_PER_PACKET_ENTRIES)) {
   1730             flags |= WifiNative.RingBufferStatus.HAS_PER_PACKET_ENTRIES;
   1731         }
   1732         if (checkoff.value != 0) {
   1733             throw new IllegalArgumentException("Unknown WifiDebugRingBufferFlag " + checkoff.value);
   1734         }
   1735         return flags;
   1736     }
   1737 
   1738     /**
   1739      * Creates array of RingBufferStatus from the Hal version
   1740      */
   1741     private static WifiNative.RingBufferStatus[] makeRingBufferStatusArray(
   1742             ArrayList<WifiDebugRingBufferStatus> ringBuffers) {
   1743         WifiNative.RingBufferStatus[] ans = new WifiNative.RingBufferStatus[ringBuffers.size()];
   1744         int i = 0;
   1745         for (WifiDebugRingBufferStatus b : ringBuffers) {
   1746             ans[i++] = ringBufferStatus(b);
   1747         }
   1748         return ans;
   1749     }
   1750 
   1751     /**
   1752      * API to get the status of all ring buffers supported by driver
   1753      */
   1754     public WifiNative.RingBufferStatus[] getRingBufferStatus() {
   1755         class AnswerBox {
   1756             public WifiNative.RingBufferStatus[] value = null;
   1757         }
   1758         AnswerBox ans = new AnswerBox();
   1759         synchronized (sLock) {
   1760             if (mIWifiChip == null) return null;
   1761             try {
   1762                 mIWifiChip.getDebugRingBuffersStatus((status, ringBuffers) -> {
   1763                     if (!ok(status)) return;
   1764                     ans.value = makeRingBufferStatusArray(ringBuffers);
   1765                 });
   1766             } catch (RemoteException e) {
   1767                 handleRemoteException(e);
   1768                 return null;
   1769             }
   1770         }
   1771         return ans.value;
   1772     }
   1773 
   1774     /**
   1775      * Indicates to driver that all the data has to be uploaded urgently
   1776      */
   1777     public boolean getRingBufferData(String ringName) {
   1778         enter("ringName %").c(ringName).flush();
   1779         synchronized (sLock) {
   1780             if (mIWifiChip == null) return boolResult(false);
   1781             try {
   1782                 WifiStatus status = mIWifiChip.forceDumpToDebugRingBuffer(ringName);
   1783                 return ok(status);
   1784             } catch (RemoteException e) {
   1785                 handleRemoteException(e);
   1786                 return false;
   1787             }
   1788         }
   1789     }
   1790 
   1791     /**
   1792      * Request vendor debug info from the firmware
   1793      */
   1794     public byte[] getFwMemoryDump() {
   1795         class AnswerBox {
   1796             public byte[] value;
   1797         }
   1798         AnswerBox ans = new AnswerBox();
   1799         synchronized (sLock) {
   1800             if (mIWifiChip == null) return (null);
   1801             try {
   1802                 mIWifiChip.requestFirmwareDebugDump((status, blob) -> {
   1803                     if (!ok(status)) return;
   1804                     ans.value = NativeUtil.byteArrayFromArrayList(blob);
   1805                 });
   1806             } catch (RemoteException e) {
   1807                 handleRemoteException(e);
   1808                 return null;
   1809             }
   1810         }
   1811         return ans.value;
   1812     }
   1813 
   1814     /**
   1815      * Request vendor debug info from the driver
   1816      */
   1817     public byte[] getDriverStateDump() {
   1818         class AnswerBox {
   1819             public byte[] value;
   1820         }
   1821         AnswerBox ans = new AnswerBox();
   1822         synchronized (sLock) {
   1823             if (mIWifiChip == null) return (null);
   1824             try {
   1825                 mIWifiChip.requestDriverDebugDump((status, blob) -> {
   1826                     if (!ok(status)) return;
   1827                     ans.value = NativeUtil.byteArrayFromArrayList(blob);
   1828                 });
   1829             } catch (RemoteException e) {
   1830                 handleRemoteException(e);
   1831                 return null;
   1832             }
   1833         }
   1834         return ans.value;
   1835     }
   1836 
   1837     /**
   1838      * Start packet fate monitoring
   1839      * <p>
   1840      * Once started, monitoring remains active until HAL is unloaded.
   1841      *
   1842      * @return true for success
   1843      */
   1844     public boolean startPktFateMonitoring() {
   1845         synchronized (sLock) {
   1846             if (mIWifiStaIface == null) return boolResult(false);
   1847             try {
   1848                 WifiStatus status = mIWifiStaIface.startDebugPacketFateMonitoring();
   1849                 return ok(status);
   1850             } catch (RemoteException e) {
   1851                 handleRemoteException(e);
   1852                 return false;
   1853             }
   1854         }
   1855     }
   1856 
   1857     private byte halToFrameworkPktFateFrameType(int type) {
   1858         switch (type) {
   1859             case WifiDebugPacketFateFrameType.UNKNOWN:
   1860                 return WifiLoggerHal.FRAME_TYPE_UNKNOWN;
   1861             case WifiDebugPacketFateFrameType.ETHERNET_II:
   1862                 return WifiLoggerHal.FRAME_TYPE_ETHERNET_II;
   1863             case WifiDebugPacketFateFrameType.MGMT_80211:
   1864                 return WifiLoggerHal.FRAME_TYPE_80211_MGMT;
   1865             default:
   1866                 throw new IllegalArgumentException("bad " + type);
   1867         }
   1868     }
   1869 
   1870     private byte halToFrameworkRxPktFate(int type) {
   1871         switch (type) {
   1872             case WifiDebugRxPacketFate.SUCCESS:
   1873                 return WifiLoggerHal.RX_PKT_FATE_SUCCESS;
   1874             case WifiDebugRxPacketFate.FW_QUEUED:
   1875                 return WifiLoggerHal.RX_PKT_FATE_FW_QUEUED;
   1876             case WifiDebugRxPacketFate.FW_DROP_FILTER:
   1877                 return WifiLoggerHal.RX_PKT_FATE_FW_DROP_FILTER;
   1878             case WifiDebugRxPacketFate.FW_DROP_INVALID:
   1879                 return WifiLoggerHal.RX_PKT_FATE_FW_DROP_INVALID;
   1880             case WifiDebugRxPacketFate.FW_DROP_NOBUFS:
   1881                 return WifiLoggerHal.RX_PKT_FATE_FW_DROP_NOBUFS;
   1882             case WifiDebugRxPacketFate.FW_DROP_OTHER:
   1883                 return WifiLoggerHal.RX_PKT_FATE_FW_DROP_OTHER;
   1884             case WifiDebugRxPacketFate.DRV_QUEUED:
   1885                 return WifiLoggerHal.RX_PKT_FATE_DRV_QUEUED;
   1886             case WifiDebugRxPacketFate.DRV_DROP_FILTER:
   1887                 return WifiLoggerHal.RX_PKT_FATE_DRV_DROP_FILTER;
   1888             case WifiDebugRxPacketFate.DRV_DROP_INVALID:
   1889                 return WifiLoggerHal.RX_PKT_FATE_DRV_DROP_INVALID;
   1890             case WifiDebugRxPacketFate.DRV_DROP_NOBUFS:
   1891                 return WifiLoggerHal.RX_PKT_FATE_DRV_DROP_NOBUFS;
   1892             case WifiDebugRxPacketFate.DRV_DROP_OTHER:
   1893                 return WifiLoggerHal.RX_PKT_FATE_DRV_DROP_OTHER;
   1894             default:
   1895                 throw new IllegalArgumentException("bad " + type);
   1896         }
   1897     }
   1898 
   1899     private byte halToFrameworkTxPktFate(int type) {
   1900         switch (type) {
   1901             case WifiDebugTxPacketFate.ACKED:
   1902                 return WifiLoggerHal.TX_PKT_FATE_ACKED;
   1903             case WifiDebugTxPacketFate.SENT:
   1904                 return WifiLoggerHal.TX_PKT_FATE_SENT;
   1905             case WifiDebugTxPacketFate.FW_QUEUED:
   1906                 return WifiLoggerHal.TX_PKT_FATE_FW_QUEUED;
   1907             case WifiDebugTxPacketFate.FW_DROP_INVALID:
   1908                 return WifiLoggerHal.TX_PKT_FATE_FW_DROP_INVALID;
   1909             case WifiDebugTxPacketFate.FW_DROP_NOBUFS:
   1910                 return WifiLoggerHal.TX_PKT_FATE_FW_DROP_NOBUFS;
   1911             case WifiDebugTxPacketFate.FW_DROP_OTHER:
   1912                 return WifiLoggerHal.TX_PKT_FATE_FW_DROP_OTHER;
   1913             case WifiDebugTxPacketFate.DRV_QUEUED:
   1914                 return WifiLoggerHal.TX_PKT_FATE_DRV_QUEUED;
   1915             case WifiDebugTxPacketFate.DRV_DROP_INVALID:
   1916                 return WifiLoggerHal.TX_PKT_FATE_DRV_DROP_INVALID;
   1917             case WifiDebugTxPacketFate.DRV_DROP_NOBUFS:
   1918                 return WifiLoggerHal.TX_PKT_FATE_DRV_DROP_NOBUFS;
   1919             case WifiDebugTxPacketFate.DRV_DROP_OTHER:
   1920                 return WifiLoggerHal.TX_PKT_FATE_DRV_DROP_OTHER;
   1921             default:
   1922                 throw new IllegalArgumentException("bad " + type);
   1923         }
   1924     }
   1925 
   1926     /**
   1927      * Retrieve fates of outbound packets
   1928      * <p>
   1929      * Reports the outbound frames for the most recent association (space allowing).
   1930      *
   1931      * @param reportBufs
   1932      * @return true for success
   1933      */
   1934     public boolean getTxPktFates(WifiNative.TxFateReport[] reportBufs) {
   1935         if (ArrayUtils.isEmpty(reportBufs)) return boolResult(false);
   1936         synchronized (sLock) {
   1937             if (mIWifiStaIface == null) return boolResult(false);
   1938             try {
   1939                 MutableBoolean ok = new MutableBoolean(false);
   1940                 mIWifiStaIface.getDebugTxPacketFates((status, fates) -> {
   1941                             if (!ok(status)) return;
   1942                             int i = 0;
   1943                             for (WifiDebugTxPacketFateReport fate : fates) {
   1944                                 if (i >= reportBufs.length) break;
   1945                                 byte code = halToFrameworkTxPktFate(fate.fate);
   1946                                 long us = fate.frameInfo.driverTimestampUsec;
   1947                                 byte type =
   1948                                         halToFrameworkPktFateFrameType(fate.frameInfo.frameType);
   1949                                 byte[] frame =
   1950                                         NativeUtil.byteArrayFromArrayList(
   1951                                                 fate.frameInfo.frameContent);
   1952                                 reportBufs[i++] =
   1953                                         new WifiNative.TxFateReport(code, us, type, frame);
   1954                             }
   1955                             ok.value = true;
   1956                         }
   1957                 );
   1958                 return ok.value;
   1959             } catch (RemoteException e) {
   1960                 handleRemoteException(e);
   1961                 return false;
   1962             }
   1963         }
   1964     }
   1965 
   1966     /**
   1967      * Retrieve fates of inbound packets
   1968      * <p>
   1969      * Reports the inbound frames for the most recent association (space allowing).
   1970      *
   1971      * @param reportBufs
   1972      * @return true for success
   1973      */
   1974     public boolean getRxPktFates(WifiNative.RxFateReport[] reportBufs) {
   1975         if (ArrayUtils.isEmpty(reportBufs)) return boolResult(false);
   1976         synchronized (sLock) {
   1977             if (mIWifiStaIface == null) return boolResult(false);
   1978             try {
   1979                 MutableBoolean ok = new MutableBoolean(false);
   1980                 mIWifiStaIface.getDebugRxPacketFates((status, fates) -> {
   1981                             if (!ok(status)) return;
   1982                             int i = 0;
   1983                             for (WifiDebugRxPacketFateReport fate : fates) {
   1984                                 if (i >= reportBufs.length) break;
   1985                                 byte code = halToFrameworkRxPktFate(fate.fate);
   1986                                 long us = fate.frameInfo.driverTimestampUsec;
   1987                                 byte type =
   1988                                         halToFrameworkPktFateFrameType(fate.frameInfo.frameType);
   1989                                 byte[] frame =
   1990                                         NativeUtil.byteArrayFromArrayList(
   1991                                                 fate.frameInfo.frameContent);
   1992                                 reportBufs[i++] =
   1993                                         new WifiNative.RxFateReport(code, us, type, frame);
   1994                             }
   1995                             ok.value = true;
   1996                         }
   1997                 );
   1998                 return ok.value;
   1999             } catch (RemoteException e) {
   2000                 handleRemoteException(e);
   2001                 return false;
   2002             }
   2003         }
   2004     }
   2005 
   2006     /**
   2007      * Start sending the specified keep alive packets periodically.
   2008      *
   2009      * @param slot
   2010      * @param srcMac
   2011      * @param keepAlivePacket
   2012      * @param periodInMs
   2013      * @return 0 for success, -1 for error
   2014      */
   2015     public int startSendingOffloadedPacket(
   2016             int slot, byte[] srcMac, KeepalivePacketData keepAlivePacket, int periodInMs) {
   2017         enter("slot=% periodInMs=%").c(slot).c(periodInMs).flush();
   2018 
   2019         ArrayList<Byte> data = NativeUtil.byteArrayToArrayList(keepAlivePacket.data);
   2020         short protocol = (short) (keepAlivePacket.protocol);
   2021 
   2022         synchronized (sLock) {
   2023             if (mIWifiStaIface == null) return -1;
   2024             try {
   2025                 WifiStatus status = mIWifiStaIface.startSendingKeepAlivePackets(
   2026                         slot,
   2027                         data,
   2028                         protocol,
   2029                         srcMac,
   2030                         keepAlivePacket.dstMac,
   2031                         periodInMs);
   2032                 if (!ok(status)) return -1;
   2033                 return 0;
   2034             } catch (RemoteException e) {
   2035                 handleRemoteException(e);
   2036                 return -1;
   2037             }
   2038         }
   2039     }
   2040 
   2041     /**
   2042      * Stop sending the specified keep alive packets.
   2043      *
   2044      * @param slot id - same as startSendingOffloadedPacket call.
   2045      * @return 0 for success, -1 for error
   2046      */
   2047     public int stopSendingOffloadedPacket(int slot) {
   2048         enter("slot=%").c(slot).flush();
   2049 
   2050         synchronized (sLock) {
   2051             if (mIWifiStaIface == null) return -1;
   2052             try {
   2053                 WifiStatus status = mIWifiStaIface.stopSendingKeepAlivePackets(slot);
   2054                 if (!ok(status)) return -1;
   2055                 return 0;
   2056             } catch (RemoteException e) {
   2057                 handleRemoteException(e);
   2058                 return -1;
   2059             }
   2060         }
   2061     }
   2062 
   2063     /**
   2064      * A fixed cmdId for our RssiMonitoring (we only do one at a time)
   2065      */
   2066     @VisibleForTesting
   2067     static final int sRssiMonCmdId = 7551;
   2068 
   2069     /**
   2070      * Our client's handler
   2071      */
   2072     private WifiNative.WifiRssiEventHandler mWifiRssiEventHandler;
   2073 
   2074     /**
   2075      * Start RSSI monitoring on the currently connected access point.
   2076      *
   2077      * @param maxRssi          Maximum RSSI threshold.
   2078      * @param minRssi          Minimum RSSI threshold.
   2079      * @param rssiEventHandler Called when RSSI goes above maxRssi or below minRssi
   2080      * @return 0 for success, -1 for failure
   2081      */
   2082     public int startRssiMonitoring(byte maxRssi, byte minRssi,
   2083                                    WifiNative.WifiRssiEventHandler rssiEventHandler) {
   2084         enter("maxRssi=% minRssi=%").c(maxRssi).c(minRssi).flush();
   2085         if (maxRssi <= minRssi) return -1;
   2086         if (rssiEventHandler == null) return -1;
   2087         synchronized (sLock) {
   2088             if (mIWifiStaIface == null) return -1;
   2089             try {
   2090                 mIWifiStaIface.stopRssiMonitoring(sRssiMonCmdId);
   2091                 WifiStatus status;
   2092                 status = mIWifiStaIface.startRssiMonitoring(sRssiMonCmdId, maxRssi, minRssi);
   2093                 if (!ok(status)) return -1;
   2094                 mWifiRssiEventHandler = rssiEventHandler;
   2095                 return 0;
   2096             } catch (RemoteException e) {
   2097                 handleRemoteException(e);
   2098                 return -1;
   2099             }
   2100         }
   2101     }
   2102 
   2103     /**
   2104      * Stop RSSI monitoring
   2105      *
   2106      * @return 0 for success, -1 for failure
   2107      */
   2108     public int stopRssiMonitoring() {
   2109         synchronized (sLock) {
   2110             mWifiRssiEventHandler = null;
   2111             if (mIWifiStaIface == null) return -1;
   2112             try {
   2113                 mIWifiStaIface.stopRssiMonitoring(sRssiMonCmdId);
   2114                 WifiStatus status = mIWifiStaIface.stopRssiMonitoring(sRssiMonCmdId);
   2115                 if (!ok(status)) return -1;
   2116                 return 0;
   2117             } catch (RemoteException e) {
   2118                 handleRemoteException(e);
   2119                 return -1;
   2120             }
   2121         }
   2122     }
   2123 
   2124     //TODO - belongs in NativeUtil
   2125     private static int[] intsFromArrayList(ArrayList<Integer> a) {
   2126         if (a == null) return null;
   2127         int[] b = new int[a.size()];
   2128         int i = 0;
   2129         for (Integer e : a) b[i++] = e;
   2130         return b;
   2131     }
   2132 
   2133     /**
   2134      * Translates from Hal version of wake reason stats to the framework version of same
   2135      *
   2136      * @param h - Hal version of wake reason stats
   2137      * @return framework version of same
   2138      */
   2139     private static WifiWakeReasonAndCounts halToFrameworkWakeReasons(
   2140             WifiDebugHostWakeReasonStats h) {
   2141         if (h == null) return null;
   2142         WifiWakeReasonAndCounts ans = new WifiWakeReasonAndCounts();
   2143         ans.totalCmdEventWake = h.totalCmdEventWakeCnt;
   2144         ans.totalDriverFwLocalWake = h.totalDriverFwLocalWakeCnt;
   2145         ans.totalRxDataWake = h.totalRxPacketWakeCnt;
   2146         ans.rxUnicast = h.rxPktWakeDetails.rxUnicastCnt;
   2147         ans.rxMulticast = h.rxPktWakeDetails.rxMulticastCnt;
   2148         ans.rxBroadcast = h.rxPktWakeDetails.rxBroadcastCnt;
   2149         ans.icmp = h.rxIcmpPkWakeDetails.icmpPkt;
   2150         ans.icmp6 = h.rxIcmpPkWakeDetails.icmp6Pkt;
   2151         ans.icmp6Ra = h.rxIcmpPkWakeDetails.icmp6Ra;
   2152         ans.icmp6Na = h.rxIcmpPkWakeDetails.icmp6Na;
   2153         ans.icmp6Ns = h.rxIcmpPkWakeDetails.icmp6Ns;
   2154         ans.ipv4RxMulticast = h.rxMulticastPkWakeDetails.ipv4RxMulticastAddrCnt;
   2155         ans.ipv6Multicast = h.rxMulticastPkWakeDetails.ipv6RxMulticastAddrCnt;
   2156         ans.otherRxMulticast = h.rxMulticastPkWakeDetails.otherRxMulticastAddrCnt;
   2157         ans.cmdEventWakeCntArray = intsFromArrayList(h.cmdEventWakeCntPerType);
   2158         ans.driverFWLocalWakeCntArray = intsFromArrayList(h.driverFwLocalWakeCntPerType);
   2159         return ans;
   2160     }
   2161 
   2162     /**
   2163      * Fetch the host wakeup reasons stats from wlan driver.
   2164      *
   2165      * @return the |WifiWakeReasonAndCounts| from the wlan driver, or null on failure.
   2166      */
   2167     public WifiWakeReasonAndCounts getWlanWakeReasonCount() {
   2168         class AnswerBox {
   2169             public WifiDebugHostWakeReasonStats value = null;
   2170         }
   2171         AnswerBox ans = new AnswerBox();
   2172         synchronized (sLock) {
   2173             if (mIWifiChip == null) return null;
   2174             try {
   2175                 mIWifiChip.getDebugHostWakeReasonStats((status, stats) -> {
   2176                     if (ok(status)) {
   2177                         ans.value = stats;
   2178                     }
   2179                 });
   2180                 return halToFrameworkWakeReasons(ans.value);
   2181             } catch (RemoteException e) {
   2182                 handleRemoteException(e);
   2183                 return null;
   2184             }
   2185         }
   2186     }
   2187 
   2188     /**
   2189      * Enable/Disable Neighbour discovery offload functionality in the firmware.
   2190      *
   2191      * @param enabled true to enable, false to disable.
   2192      */
   2193     public boolean configureNeighborDiscoveryOffload(boolean enabled) {
   2194         enter("enabled=%").c(enabled).flush();
   2195         synchronized (sLock) {
   2196             if (mIWifiStaIface == null) return boolResult(false);
   2197             try {
   2198                 WifiStatus status = mIWifiStaIface.enableNdOffload(enabled);
   2199                 if (!ok(status)) return false;
   2200             } catch (RemoteException e) {
   2201                 handleRemoteException(e);
   2202                 return false;
   2203             }
   2204         }
   2205         return true;
   2206     }
   2207 
   2208     // Firmware roaming control.
   2209 
   2210     /**
   2211      * Query the firmware roaming capabilities.
   2212      *
   2213      * @param capabilities object to be filled in
   2214      * @return true for success; false for failure
   2215      */
   2216     public boolean getRoamingCapabilities(WifiNative.RoamingCapabilities capabilities) {
   2217         synchronized (sLock) {
   2218             if (mIWifiStaIface == null) return boolResult(false);
   2219             try {
   2220                 MutableBoolean ok = new MutableBoolean(false);
   2221                 WifiNative.RoamingCapabilities out = capabilities;
   2222                 mIWifiStaIface.getRoamingCapabilities((status, cap) -> {
   2223                     if (!ok(status)) return;
   2224                     out.maxBlacklistSize = cap.maxBlacklistSize;
   2225                     out.maxWhitelistSize = cap.maxWhitelistSize;
   2226                     ok.value = true;
   2227                 });
   2228                 return ok.value;
   2229             } catch (RemoteException e) {
   2230                 handleRemoteException(e);
   2231                 return false;
   2232             }
   2233         }
   2234     }
   2235 
   2236     /**
   2237      * Enable/disable firmware roaming.
   2238      *
   2239      * @param state the intended roaming state
   2240      * @return SUCCESS, FAILURE, or BUSY
   2241      */
   2242     public int enableFirmwareRoaming(int state) {
   2243         synchronized (sLock) {
   2244             if (mIWifiStaIface == null) return WifiStatusCode.ERROR_NOT_STARTED;
   2245             try {
   2246                 byte val;
   2247                 switch (state) {
   2248                     case WifiNative.DISABLE_FIRMWARE_ROAMING:
   2249                         val = StaRoamingState.DISABLED;
   2250                         break;
   2251                     case WifiNative.ENABLE_FIRMWARE_ROAMING:
   2252                         val = StaRoamingState.ENABLED;
   2253                         break;
   2254                     default:
   2255                         mLog.e("enableFirmwareRoaming invalid argument " + state);
   2256                         return WifiStatusCode.ERROR_INVALID_ARGS;
   2257                 }
   2258 
   2259                 WifiStatus status = mIWifiStaIface.setRoamingState(val);
   2260                 mVerboseLog.d("setRoamingState returned " + status.code);
   2261                 return status.code;
   2262             } catch (RemoteException e) {
   2263                 handleRemoteException(e);
   2264                 return WifiStatusCode.ERROR_UNKNOWN;
   2265             }
   2266         }
   2267     }
   2268 
   2269     /**
   2270      * Set firmware roaming configurations.
   2271      *
   2272      * @param config new roaming configuration object
   2273      * @return true for success; false for failure
   2274      */
   2275     public boolean configureRoaming(WifiNative.RoamingConfig config) {
   2276         synchronized (sLock) {
   2277             if (mIWifiStaIface == null) return boolResult(false);
   2278             try {
   2279                 StaRoamingConfig roamingConfig = new StaRoamingConfig();
   2280 
   2281                 // parse the blacklist BSSIDs if any
   2282                 if (config.blacklistBssids != null) {
   2283                     for (String bssid : config.blacklistBssids) {
   2284                         byte[] mac = NativeUtil.macAddressToByteArray(bssid);
   2285                         roamingConfig.bssidBlacklist.add(mac);
   2286                     }
   2287                 }
   2288 
   2289                 // parse the whitelist SSIDs if any
   2290                 if (config.whitelistSsids != null) {
   2291                     for (String ssidStr : config.whitelistSsids) {
   2292                         String unquotedSsidStr = WifiInfo.removeDoubleQuotes(ssidStr);
   2293 
   2294                         int len = unquotedSsidStr.length();
   2295                         if (len > 32) {
   2296                             mLog.err("configureRoaming: skip invalid SSID %")
   2297                                     .r(unquotedSsidStr).flush();
   2298                             continue;
   2299                         }
   2300                         byte[] ssid = new byte[len];
   2301                         for (int i = 0; i < len; i++) {
   2302                             ssid[i] = (byte) unquotedSsidStr.charAt(i);
   2303                         }
   2304                         roamingConfig.ssidWhitelist.add(ssid);
   2305                     }
   2306                 }
   2307 
   2308                 WifiStatus status = mIWifiStaIface.configureRoaming(roamingConfig);
   2309                 if (!ok(status)) return false;
   2310             } catch (RemoteException e) {
   2311                 handleRemoteException(e);
   2312                 return false;
   2313             } catch (IllegalArgumentException e) {
   2314                 mLog.err("Illegal argument for roaming configuration").c(e.toString()).flush();
   2315                 return false;
   2316             }
   2317             return true;
   2318         }
   2319     }
   2320 
   2321     // This creates a blob of IE elements from the array received.
   2322     // TODO: This ugly conversion can be removed if we put IE elements in ScanResult.
   2323     private static byte[] hidlIeArrayToFrameworkIeBlob(ArrayList<WifiInformationElement> ies) {
   2324         if (ies == null || ies.isEmpty()) return new byte[0];
   2325         ArrayList<Byte> ieBlob = new ArrayList<>();
   2326         for (WifiInformationElement ie : ies) {
   2327             ieBlob.add(ie.id);
   2328             ieBlob.addAll(ie.data);
   2329         }
   2330         return NativeUtil.byteArrayFromArrayList(ieBlob);
   2331     }
   2332 
   2333     // This is only filling up the fields of Scan Result used by Gscan clients.
   2334     private static ScanResult hidlToFrameworkScanResult(StaScanResult scanResult) {
   2335         if (scanResult == null) return null;
   2336         ScanResult frameworkScanResult = new ScanResult();
   2337         frameworkScanResult.SSID = NativeUtil.encodeSsid(scanResult.ssid);
   2338         frameworkScanResult.wifiSsid =
   2339                 WifiSsid.createFromByteArray(NativeUtil.byteArrayFromArrayList(scanResult.ssid));
   2340         frameworkScanResult.BSSID = NativeUtil.macAddressFromByteArray(scanResult.bssid);
   2341         frameworkScanResult.level = scanResult.rssi;
   2342         frameworkScanResult.frequency = scanResult.frequency;
   2343         frameworkScanResult.timestamp = scanResult.timeStampInUs;
   2344         frameworkScanResult.bytes = hidlIeArrayToFrameworkIeBlob(scanResult.informationElements);
   2345         return frameworkScanResult;
   2346     }
   2347 
   2348     private static ScanResult[] hidlToFrameworkScanResults(ArrayList<StaScanResult> scanResults) {
   2349         if (scanResults == null || scanResults.isEmpty()) return new ScanResult[0];
   2350         ScanResult[] frameworkScanResults = new ScanResult[scanResults.size()];
   2351         int i = 0;
   2352         for (StaScanResult scanResult : scanResults) {
   2353             frameworkScanResults[i++] = hidlToFrameworkScanResult(scanResult);
   2354         }
   2355         return frameworkScanResults;
   2356     }
   2357 
   2358     /**
   2359      * This just returns whether the scan was interrupted or not.
   2360      */
   2361     private static int hidlToFrameworkScanDataFlags(int flag) {
   2362         if (flag == StaScanDataFlagMask.INTERRUPTED) {
   2363             return 1;
   2364         } else {
   2365             return 0;
   2366         }
   2367     }
   2368 
   2369     private static WifiScanner.ScanData[] hidlToFrameworkScanDatas(
   2370             int cmdId, ArrayList<StaScanData> scanDatas) {
   2371         if (scanDatas == null || scanDatas.isEmpty()) return new WifiScanner.ScanData[0];
   2372         WifiScanner.ScanData[] frameworkScanDatas = new WifiScanner.ScanData[scanDatas.size()];
   2373         int i = 0;
   2374         for (StaScanData scanData : scanDatas) {
   2375             int flags = hidlToFrameworkScanDataFlags(scanData.flags);
   2376             ScanResult[] frameworkScanResults = hidlToFrameworkScanResults(scanData.results);
   2377             frameworkScanDatas[i++] =
   2378                     new WifiScanner.ScanData(cmdId, flags, scanData.bucketsScanned, false,
   2379                             frameworkScanResults);
   2380         }
   2381         return frameworkScanDatas;
   2382     }
   2383 
   2384     /**
   2385      * Callback for events on the STA interface.
   2386      */
   2387     private class StaIfaceEventCallback extends IWifiStaIfaceEventCallback.Stub {
   2388         @Override
   2389         public void onBackgroundScanFailure(int cmdId) {
   2390             mVerboseLog.d("onBackgroundScanFailure " + cmdId);
   2391             WifiNative.ScanEventHandler eventHandler;
   2392             synchronized (sLock) {
   2393                 if (mScan == null || cmdId != mScan.cmdId) return;
   2394                 eventHandler = mScan.eventHandler;
   2395             }
   2396             eventHandler.onScanStatus(WifiNative.WIFI_SCAN_FAILED);
   2397         }
   2398 
   2399         @Override
   2400         public void onBackgroundFullScanResult(
   2401                 int cmdId, int bucketsScanned, StaScanResult result) {
   2402             mVerboseLog.d("onBackgroundFullScanResult " + cmdId);
   2403             WifiNative.ScanEventHandler eventHandler;
   2404             synchronized (sLock) {
   2405                 if (mScan == null || cmdId != mScan.cmdId) return;
   2406                 eventHandler = mScan.eventHandler;
   2407             }
   2408             eventHandler.onFullScanResult(hidlToFrameworkScanResult(result), bucketsScanned);
   2409         }
   2410 
   2411         @Override
   2412         public void onBackgroundScanResults(int cmdId, ArrayList<StaScanData> scanDatas) {
   2413             mVerboseLog.d("onBackgroundScanResults " + cmdId);
   2414             WifiNative.ScanEventHandler eventHandler;
   2415             // WifiScanner currently uses the results callback to fetch the scan results.
   2416             // So, simulate that by sending out the notification and then caching the results
   2417             // locally. This will then be returned to WifiScanner via getScanResults.
   2418             synchronized (sLock) {
   2419                 if (mScan == null || cmdId != mScan.cmdId) return;
   2420                 eventHandler = mScan.eventHandler;
   2421                 mScan.latestScanResults = hidlToFrameworkScanDatas(cmdId, scanDatas);
   2422             }
   2423             eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
   2424         }
   2425 
   2426         @Override
   2427         public void onRssiThresholdBreached(int cmdId, byte[/* 6 */] currBssid, int currRssi) {
   2428             mVerboseLog.d("onRssiThresholdBreached " + cmdId + "currRssi " + currRssi);
   2429             WifiNative.WifiRssiEventHandler eventHandler;
   2430             synchronized (sLock) {
   2431                 if (mWifiRssiEventHandler == null || cmdId != sRssiMonCmdId) return;
   2432                 eventHandler = mWifiRssiEventHandler;
   2433             }
   2434             eventHandler.onRssiThresholdBreached((byte) currRssi);
   2435         }
   2436     }
   2437 
   2438     /**
   2439      * Callback for events on the STA interface.
   2440      */
   2441     private class ChipEventCallback extends IWifiChipEventCallback.Stub {
   2442         @Override
   2443         public void onChipReconfigured(int modeId) {
   2444             mVerboseLog.d("onChipReconfigured " + modeId);
   2445         }
   2446 
   2447         @Override
   2448         public void onChipReconfigureFailure(WifiStatus status) {
   2449             mVerboseLog.d("onChipReconfigureFailure " + status);
   2450         }
   2451 
   2452         public void onIfaceAdded(int type, String name) {
   2453             mVerboseLog.d("onIfaceAdded " + type + ", name: " + name);
   2454         }
   2455 
   2456         @Override
   2457         public void onIfaceRemoved(int type, String name) {
   2458             mVerboseLog.d("onIfaceRemoved " + type + ", name: " + name);
   2459         }
   2460 
   2461         @Override
   2462         public void onDebugRingBufferDataAvailable(
   2463                 WifiDebugRingBufferStatus status, java.util.ArrayList<Byte> data) {
   2464             //TODO(b/35875078) Reinstate logging when execessive callbacks are fixed
   2465             // mVerboseLog.d("onDebugRingBufferDataAvailable " + status);
   2466             mHalEventHandler.post(() -> {
   2467                 WifiNative.WifiLoggerEventHandler eventHandler;
   2468                 synchronized (sLock) {
   2469                     if (mLogEventHandler == null || status == null || data == null) return;
   2470                     eventHandler = mLogEventHandler;
   2471                 }
   2472                 // Because |sLock| has been released, there is a chance that we'll execute
   2473                 // a spurious callback (after someone has called resetLogHandler()).
   2474                 //
   2475                 // However, the alternative risks deadlock. Consider:
   2476                 // [T1.1] WifiDiagnostics.captureBugReport()
   2477                 // [T1.2] -- acquire WifiDiagnostics object's intrinsic lock
   2478                 // [T1.3]    -> WifiVendorHal.getRingBufferData()
   2479                 // [T1.4]       -- acquire WifiVendorHal.sLock
   2480                 // [T2.1] <lambda>()
   2481                 // [T2.2] -- acquire WifiVendorHal.sLock
   2482                 // [T2.3]    -> WifiDiagnostics.onRingBufferData()
   2483                 // [T2.4]       -- acquire WifiDiagnostics object's intrinsic lock
   2484                 //
   2485                 // The problem here is that the two threads acquire the locks in opposite order.
   2486                 // If, for example, T2.2 executes between T1.2 and 1.4, then T1 and T2
   2487                 // will be deadlocked.
   2488                 eventHandler.onRingBufferData(
   2489                         ringBufferStatus(status), NativeUtil.byteArrayFromArrayList(data));
   2490             });
   2491         }
   2492 
   2493         @Override
   2494         public void onDebugErrorAlert(int errorCode, java.util.ArrayList<Byte> debugData) {
   2495             mVerboseLog.d("onDebugErrorAlert " + errorCode);
   2496             mHalEventHandler.post(() -> {
   2497                 WifiNative.WifiLoggerEventHandler eventHandler;
   2498                 synchronized (sLock) {
   2499                     if (mLogEventHandler == null || debugData == null) return;
   2500                     eventHandler = mLogEventHandler;
   2501                 }
   2502                 // See comment in onDebugRingBufferDataAvailable(), for an explanation
   2503                 // of why this callback is invoked without |sLock| held.
   2504                 eventHandler.onWifiAlert(
   2505                         errorCode, NativeUtil.byteArrayFromArrayList(debugData));
   2506             });
   2507         }
   2508     }
   2509 
   2510     /**
   2511      * Hal Device Manager callbacks.
   2512      */
   2513     public class HalDeviceManagerStatusListener implements HalDeviceManager.ManagerStatusListener {
   2514         @Override
   2515         public void onStatusChanged() {
   2516             boolean isReady = mHalDeviceManager.isReady();
   2517             boolean isStarted = mHalDeviceManager.isStarted();
   2518 
   2519             mVerboseLog.i("Device Manager onStatusChanged. isReady(): " + isReady
   2520                     + ", isStarted(): " + isStarted);
   2521             if (!isReady) {
   2522                 // Probably something unpleasant, e.g. the server died
   2523                 WifiNative.VendorHalDeathEventHandler handler;
   2524                 synchronized (sLock) {
   2525                     clearState();
   2526                     handler = mDeathEventHandler;
   2527                 }
   2528                 if (handler != null) {
   2529                     handler.onDeath();
   2530                 }
   2531             }
   2532         }
   2533     }
   2534 }
   2535