Home | History | Annotate | Download | only in rtt
      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 
     17 package com.android.server.wifi.rtt;
     18 
     19 import android.hardware.wifi.V1_0.IWifiRttController;
     20 import android.hardware.wifi.V1_0.IWifiRttControllerEventCallback;
     21 import android.hardware.wifi.V1_0.RttBw;
     22 import android.hardware.wifi.V1_0.RttCapabilities;
     23 import android.hardware.wifi.V1_0.RttConfig;
     24 import android.hardware.wifi.V1_0.RttPeerType;
     25 import android.hardware.wifi.V1_0.RttPreamble;
     26 import android.hardware.wifi.V1_0.RttResult;
     27 import android.hardware.wifi.V1_0.RttType;
     28 import android.hardware.wifi.V1_0.WifiChannelWidthInMhz;
     29 import android.hardware.wifi.V1_0.WifiStatus;
     30 import android.hardware.wifi.V1_0.WifiStatusCode;
     31 import android.net.wifi.rtt.RangingRequest;
     32 import android.net.wifi.rtt.ResponderConfig;
     33 import android.os.Handler;
     34 import android.os.RemoteException;
     35 import android.util.Log;
     36 
     37 import com.android.server.wifi.HalDeviceManager;
     38 
     39 import java.io.FileDescriptor;
     40 import java.io.PrintWriter;
     41 import java.util.ArrayList;
     42 import java.util.ListIterator;
     43 
     44 /**
     45  * TBD
     46  */
     47 public class RttNative extends IWifiRttControllerEventCallback.Stub {
     48     private static final String TAG = "RttNative";
     49     private static final boolean VDBG = false; // STOPSHIP if true
     50     /* package */ boolean mDbg = false;
     51 
     52     private final RttServiceImpl mRttService;
     53     private final HalDeviceManager mHalDeviceManager;
     54 
     55     private Object mLock = new Object();
     56 
     57     private volatile IWifiRttController mIWifiRttController;
     58     private volatile RttCapabilities mRttCapabilities;
     59 
     60     public RttNative(RttServiceImpl rttService, HalDeviceManager halDeviceManager) {
     61         mRttService = rttService;
     62         mHalDeviceManager = halDeviceManager;
     63     }
     64 
     65     /**
     66      * Initialize the object - registering with the HAL device manager.
     67      */
     68     public void start(Handler handler) {
     69         synchronized (mLock) {
     70             mHalDeviceManager.initialize();
     71             mHalDeviceManager.registerStatusListener(() -> {
     72                 if (VDBG) Log.d(TAG, "hdm.onStatusChanged");
     73                 updateController();
     74             }, handler);
     75             updateController();
     76         }
     77     }
     78 
     79     /**
     80      * Returns true if Wi-Fi is ready for RTT requests, false otherwise.
     81      */
     82     public boolean isReady() {
     83         return mIWifiRttController != null;
     84     }
     85 
     86     private void updateController() {
     87         if (mDbg) Log.v(TAG, "updateController: mIWifiRttController=" + mIWifiRttController);
     88 
     89         // only care about isStarted (Wi-Fi started) not isReady - since if not
     90         // ready then Wi-Fi will also be down.
     91         synchronized (mLock) {
     92             IWifiRttController localWifiRttController = mIWifiRttController;
     93             if (mHalDeviceManager.isStarted()) {
     94                 if (localWifiRttController == null) {
     95                     localWifiRttController = mHalDeviceManager.createRttController();
     96                     if (localWifiRttController == null) {
     97                         Log.e(TAG, "updateController: Failed creating RTT controller - but Wifi is "
     98                                 + "started!");
     99                     } else {
    100                         try {
    101                             localWifiRttController.registerEventCallback(this);
    102                         } catch (RemoteException e) {
    103                             Log.e(TAG, "updateController: exception registering callback: " + e);
    104                             localWifiRttController = null;
    105                         }
    106                     }
    107                 }
    108             } else {
    109                 localWifiRttController = null;
    110             }
    111             mIWifiRttController = localWifiRttController;
    112 
    113             if (mIWifiRttController == null) {
    114                 mRttService.disable();
    115             } else {
    116                 mRttService.enableIfPossible();
    117                 updateRttCapabilities();
    118             }
    119         }
    120     }
    121 
    122     /**
    123      * Updates the RTT capabilities.
    124      */
    125     void updateRttCapabilities() {
    126         if (mRttCapabilities != null) {
    127             return;
    128         }
    129 
    130         synchronized (mLock) {
    131             try {
    132                 mIWifiRttController.getCapabilities(
    133                         (status, capabilities) -> {
    134                             if (status.code != WifiStatusCode.SUCCESS) {
    135                                 Log.e(TAG,
    136                                         "updateController: error requesting capabilities -- code="
    137                                                 + status.code);
    138                                 return;
    139                             }
    140                             if (mDbg) {
    141                                 Log.v(TAG, "updateController: RTT capabilities=" + capabilities);
    142                             }
    143                             mRttCapabilities = capabilities;
    144                         });
    145             } catch (RemoteException e) {
    146                 Log.e(TAG, "updateController: exception requesting capabilities: " + e);
    147             }
    148 
    149             if (mRttCapabilities != null && !mRttCapabilities.rttFtmSupported) {
    150                 Log.wtf(TAG, "Firmware indicates RTT is not supported - but device supports RTT - "
    151                         + "ignored!?");
    152             }
    153         }
    154     }
    155 
    156     /**
    157      * Issue a range request to the HAL.
    158      *
    159      * @param cmdId Command ID for the request. Will be used in the corresponding
    160      * {@link #onResults(int, ArrayList)}.
    161      * @param request Range request.
    162      * @param isCalledFromPrivilegedContext Indicates whether privileged APIs are permitted,
    163      *                                      initially: support for one-sided RTT.
    164      *
    165      * @return Success status: true for success, false for failure.
    166      */
    167     public boolean rangeRequest(int cmdId, RangingRequest request,
    168             boolean isCalledFromPrivilegedContext) {
    169         if (mDbg) {
    170             Log.v(TAG,
    171                     "rangeRequest: cmdId=" + cmdId + ", # of requests=" + request.mRttPeers.size());
    172         }
    173         if (VDBG) Log.v(TAG, "rangeRequest: request=" + request);
    174         updateRttCapabilities();
    175         synchronized (mLock) {
    176             if (!isReady()) {
    177                 Log.e(TAG, "rangeRequest: RttController is null");
    178                 return false;
    179             }
    180 
    181             ArrayList<RttConfig> rttConfig = convertRangingRequestToRttConfigs(request,
    182                     isCalledFromPrivilegedContext, mRttCapabilities);
    183             if (rttConfig == null) {
    184                 Log.e(TAG, "rangeRequest: invalid request parameters");
    185                 return false;
    186             }
    187             if (rttConfig.size() == 0) {
    188                 Log.e(TAG, "rangeRequest: all requests invalidated");
    189                 mRttService.onRangingResults(cmdId, new ArrayList<>());
    190                 return true;
    191             }
    192 
    193             try {
    194                 WifiStatus status = mIWifiRttController.rangeRequest(cmdId, rttConfig);
    195                 if (status.code != WifiStatusCode.SUCCESS) {
    196                     Log.e(TAG, "rangeRequest: cannot issue range request -- code=" + status.code);
    197                     return false;
    198                 }
    199             } catch (RemoteException e) {
    200                 Log.e(TAG, "rangeRequest: exception issuing range request: " + e);
    201                 return false;
    202             }
    203 
    204             return true;
    205         }
    206     }
    207 
    208     /**
    209      * Cancel an outstanding ranging request: no guarantees of execution - we will ignore any
    210      * results which are returned for the canceled request.
    211      *
    212      * @param cmdId The cmdId issued with the original rangeRequest command.
    213      * @param macAddresses A list of MAC addresses for which to cancel the operation.
    214      * @return Success status: true for success, false for failure.
    215      */
    216     public boolean rangeCancel(int cmdId, ArrayList<byte[]> macAddresses) {
    217         if (mDbg) Log.v(TAG, "rangeCancel: cmdId=" + cmdId);
    218         synchronized (mLock) {
    219             if (!isReady()) {
    220                 Log.e(TAG, "rangeCancel: RttController is null");
    221                 return false;
    222             }
    223 
    224             try {
    225                 WifiStatus status = mIWifiRttController.rangeCancel(cmdId, macAddresses);
    226                 if (status.code != WifiStatusCode.SUCCESS) {
    227                     Log.e(TAG, "rangeCancel: cannot issue range cancel -- code=" + status.code);
    228                     return false;
    229                 }
    230             } catch (RemoteException e) {
    231                 Log.e(TAG, "rangeCancel: exception issuing range cancel: " + e);
    232                 return false;
    233             }
    234 
    235             return true;
    236         }
    237     }
    238 
    239     /**
    240      * Callback from HAL with range results.
    241      *
    242      * @param cmdId Command ID specified in the original request
    243      * {@link #rangeRequest(int, RangingRequest, boolean)}.
    244      * @param halResults A list of range results.
    245      */
    246     @Override
    247     public void onResults(int cmdId, ArrayList<RttResult> halResults) {
    248         if (mDbg) Log.v(TAG, "onResults: cmdId=" + cmdId + ", # of results=" + halResults.size());
    249 
    250         // sanitize HAL results
    251         if (halResults == null) {
    252             halResults = new ArrayList<>();
    253         }
    254         ListIterator<RttResult> lit = halResults.listIterator();
    255         while (lit.hasNext()) {
    256             if (lit.next() == null) {
    257                 lit.remove();
    258             }
    259         }
    260         mRttService.onRangingResults(cmdId, halResults);
    261     }
    262 
    263     private static ArrayList<RttConfig> convertRangingRequestToRttConfigs(RangingRequest request,
    264             boolean isCalledFromPrivilegedContext, RttCapabilities cap) {
    265         ArrayList<RttConfig> rttConfigs = new ArrayList<>(request.mRttPeers.size());
    266 
    267         // Skipping any configurations which have an error (printing out a message).
    268         // The caller will only get results for valid configurations.
    269         for (ResponderConfig responder: request.mRttPeers) {
    270             if (!isCalledFromPrivilegedContext) {
    271                 if (!responder.supports80211mc) {
    272                     Log.e(TAG, "Invalid responder: does not support 802.11mc");
    273                     continue;
    274                 }
    275             }
    276 
    277             RttConfig config = new RttConfig();
    278 
    279             System.arraycopy(responder.macAddress.toByteArray(), 0, config.addr, 0,
    280                     config.addr.length);
    281 
    282             try {
    283                 config.type = responder.supports80211mc ? RttType.TWO_SIDED : RttType.ONE_SIDED;
    284                 if (config.type == RttType.ONE_SIDED && cap != null && !cap.rttOneSidedSupported) {
    285                     Log.w(TAG, "Device does not support one-sided RTT");
    286                     continue;
    287                 }
    288 
    289                 config.peer = halRttPeerTypeFromResponderType(responder.responderType);
    290                 config.channel.width = halChannelWidthFromResponderChannelWidth(
    291                         responder.channelWidth);
    292                 config.channel.centerFreq = responder.frequency;
    293                 config.channel.centerFreq0 = responder.centerFreq0;
    294                 config.channel.centerFreq1 = responder.centerFreq1;
    295                 config.bw = halRttChannelBandwidthFromResponderChannelWidth(responder.channelWidth);
    296                 config.preamble = halRttPreambleFromResponderPreamble(responder.preamble);
    297 
    298                 if (config.peer == RttPeerType.NAN) {
    299                     config.mustRequestLci = false;
    300                     config.mustRequestLcr = false;
    301                     config.burstPeriod = 0;
    302                     config.numBurst = 0;
    303                     config.numFramesPerBurst = 5;
    304                     config.numRetriesPerRttFrame = 0; // irrelevant for 2-sided RTT
    305                     config.numRetriesPerFtmr = 3;
    306                     config.burstDuration = 9;
    307                 } else { // AP + all non-NAN requests
    308                     config.mustRequestLci = isCalledFromPrivilegedContext;
    309                     config.mustRequestLcr = isCalledFromPrivilegedContext;
    310                     config.burstPeriod = 0;
    311                     config.numBurst = 0;
    312                     config.numFramesPerBurst = 8;
    313                     config.numRetriesPerRttFrame = (config.type == RttType.TWO_SIDED ? 0 : 3);
    314                     config.numRetriesPerFtmr = 3;
    315                     config.burstDuration = 9;
    316 
    317                     if (cap != null) { // constrain parameters per device capabilities
    318                         config.mustRequestLci = config.mustRequestLci && cap.lciSupported;
    319                         config.mustRequestLcr = config.mustRequestLcr && cap.lcrSupported;
    320                         config.bw = halRttChannelBandwidthCapabilityLimiter(config.bw, cap);
    321                         config.preamble = halRttPreambleCapabilityLimiter(config.preamble, cap);
    322                     }
    323                 }
    324             } catch (IllegalArgumentException e) {
    325                 Log.e(TAG, "Invalid configuration: " + e.getMessage());
    326                 continue;
    327             }
    328 
    329             rttConfigs.add(config);
    330         }
    331 
    332         return rttConfigs;
    333     }
    334 
    335     private static int halRttPeerTypeFromResponderType(int responderType) {
    336         switch (responderType) {
    337             case ResponderConfig.RESPONDER_AP:
    338                 return RttPeerType.AP;
    339             case ResponderConfig.RESPONDER_STA:
    340                 return RttPeerType.STA;
    341             case ResponderConfig.RESPONDER_P2P_GO:
    342                 return RttPeerType.P2P_GO;
    343             case ResponderConfig.RESPONDER_P2P_CLIENT:
    344                 return RttPeerType.P2P_CLIENT;
    345             case ResponderConfig.RESPONDER_AWARE:
    346                 return RttPeerType.NAN;
    347             default:
    348                 throw new IllegalArgumentException(
    349                         "halRttPeerTypeFromResponderType: bad " + responderType);
    350         }
    351     }
    352 
    353     private static int halChannelWidthFromResponderChannelWidth(int responderChannelWidth) {
    354         switch (responderChannelWidth) {
    355             case ResponderConfig.CHANNEL_WIDTH_20MHZ:
    356                 return WifiChannelWidthInMhz.WIDTH_20;
    357             case ResponderConfig.CHANNEL_WIDTH_40MHZ:
    358                 return WifiChannelWidthInMhz.WIDTH_40;
    359             case ResponderConfig.CHANNEL_WIDTH_80MHZ:
    360                 return WifiChannelWidthInMhz.WIDTH_80;
    361             case ResponderConfig.CHANNEL_WIDTH_160MHZ:
    362                 return WifiChannelWidthInMhz.WIDTH_160;
    363             case ResponderConfig.CHANNEL_WIDTH_80MHZ_PLUS_MHZ:
    364                 return WifiChannelWidthInMhz.WIDTH_80P80;
    365             default:
    366                 throw new IllegalArgumentException(
    367                         "halChannelWidthFromResponderChannelWidth: bad " + responderChannelWidth);
    368         }
    369     }
    370 
    371     private static int halRttChannelBandwidthFromResponderChannelWidth(int responderChannelWidth) {
    372         switch (responderChannelWidth) {
    373             case ResponderConfig.CHANNEL_WIDTH_20MHZ:
    374                 return RttBw.BW_20MHZ;
    375             case ResponderConfig.CHANNEL_WIDTH_40MHZ:
    376                 return RttBw.BW_40MHZ;
    377             case ResponderConfig.CHANNEL_WIDTH_80MHZ:
    378                 return RttBw.BW_80MHZ;
    379             case ResponderConfig.CHANNEL_WIDTH_160MHZ:
    380                 return RttBw.BW_160MHZ;
    381             case ResponderConfig.CHANNEL_WIDTH_80MHZ_PLUS_MHZ:
    382                 return RttBw.BW_160MHZ;
    383             default:
    384                 throw new IllegalArgumentException(
    385                         "halRttChannelBandwidthFromHalBandwidth: bad " + responderChannelWidth);
    386         }
    387     }
    388 
    389     private static int halRttPreambleFromResponderPreamble(int responderPreamble) {
    390         switch (responderPreamble) {
    391             case ResponderConfig.PREAMBLE_LEGACY:
    392                 return RttPreamble.LEGACY;
    393             case ResponderConfig.PREAMBLE_HT:
    394                 return RttPreamble.HT;
    395             case ResponderConfig.PREAMBLE_VHT:
    396                 return RttPreamble.VHT;
    397             default:
    398                 throw new IllegalArgumentException(
    399                         "halRttPreambleFromResponderPreamble: bad " + responderPreamble);
    400         }
    401     }
    402 
    403     /**
    404      * Check to see whether the selected RTT channel bandwidth is supported by the device.
    405      * If not supported: return the next lower bandwidth which is supported
    406      * If none: throw an IllegalArgumentException.
    407      *
    408      * Note: the halRttChannelBandwidth is a single bit flag of the ones used in cap.bwSupport (HAL
    409      * specifications).
    410      */
    411     private static int halRttChannelBandwidthCapabilityLimiter(int halRttChannelBandwidth,
    412             RttCapabilities cap) {
    413         while ((halRttChannelBandwidth != 0) && ((halRttChannelBandwidth & cap.bwSupport) == 0)) {
    414             halRttChannelBandwidth >>= 1;
    415         }
    416 
    417         if (halRttChannelBandwidth != 0) {
    418             return halRttChannelBandwidth;
    419         }
    420 
    421         throw new IllegalArgumentException(
    422                 "RTT BW=" + halRttChannelBandwidth + ", not supported by device capabilities=" + cap
    423                         + " - and no supported alternative");
    424     }
    425 
    426     /**
    427      * Check to see whether the selected RTT preamble is supported by the device.
    428      * If not supported: return the next "lower" preamble which is supported
    429      * If none: throw an IllegalArgumentException.
    430      *
    431      * Note: the halRttPreamble is a single bit flag of the ones used in cap.preambleSupport (HAL
    432      * specifications).
    433      */
    434     private static int halRttPreambleCapabilityLimiter(int halRttPreamble, RttCapabilities cap) {
    435         while ((halRttPreamble != 0) && ((halRttPreamble & cap.preambleSupport) == 0)) {
    436             halRttPreamble >>= 1;
    437         }
    438 
    439         if (halRttPreamble != 0) {
    440             return halRttPreamble;
    441         }
    442 
    443         throw new IllegalArgumentException(
    444                 "RTT Preamble=" + halRttPreamble + ", not supported by device capabilities=" + cap
    445                         + " - and no supported alternative");
    446     }
    447 
    448 
    449     /**
    450      * Dump the internal state of the class.
    451      */
    452     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    453         pw.println("RttNative:");
    454         pw.println("  mHalDeviceManager: " + mHalDeviceManager);
    455         pw.println("  mIWifiRttController: " + mIWifiRttController);
    456         pw.println("  mRttCapabilities: " + mRttCapabilities);
    457     }
    458 }
    459