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