Home | History | Annotate | Download | only in aware
      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.aware;
     18 
     19 import android.hardware.wifi.V1_0.IWifiNanIfaceEventCallback;
     20 import android.hardware.wifi.V1_0.NanCapabilities;
     21 import android.hardware.wifi.V1_0.NanClusterEventInd;
     22 import android.hardware.wifi.V1_0.NanClusterEventType;
     23 import android.hardware.wifi.V1_0.NanDataPathConfirmInd;
     24 import android.hardware.wifi.V1_0.NanDataPathRequestInd;
     25 import android.hardware.wifi.V1_0.NanFollowupReceivedInd;
     26 import android.hardware.wifi.V1_0.NanMatchInd;
     27 import android.hardware.wifi.V1_0.NanStatusType;
     28 import android.hardware.wifi.V1_0.WifiNanStatus;
     29 import android.os.ShellCommand;
     30 import android.util.Log;
     31 import android.util.SparseIntArray;
     32 
     33 import libcore.util.HexEncoding;
     34 
     35 import org.json.JSONException;
     36 import org.json.JSONObject;
     37 
     38 import java.io.FileDescriptor;
     39 import java.io.PrintWriter;
     40 import java.util.ArrayList;
     41 import java.util.Arrays;
     42 
     43 /**
     44  * Manages the callbacks from Wi-Fi Aware HIDL (HAL).
     45  */
     46 public class WifiAwareNativeCallback extends IWifiNanIfaceEventCallback.Stub implements
     47         WifiAwareShellCommand.DelegatedShellCommand {
     48     private static final String TAG = "WifiAwareNativeCallback";
     49     private static final boolean DBG = false;
     50     private static final boolean VDBG = false;
     51 
     52     private final WifiAwareStateManager mWifiAwareStateManager;
     53 
     54     public WifiAwareNativeCallback(WifiAwareStateManager wifiAwareStateManager) {
     55         mWifiAwareStateManager = wifiAwareStateManager;
     56     }
     57 
     58     /*
     59      * Counts of callbacks from HAL. Retrievable through shell command.
     60      */
     61     private static final int CB_EV_CLUSTER = 0;
     62     private static final int CB_EV_DISABLED = 1;
     63     private static final int CB_EV_PUBLISH_TERMINATED = 2;
     64     private static final int CB_EV_SUBSCRIBE_TERMINATED = 3;
     65     private static final int CB_EV_MATCH = 4;
     66     private static final int CB_EV_MATCH_EXPIRED = 5;
     67     private static final int CB_EV_FOLLOWUP_RECEIVED = 6;
     68     private static final int CB_EV_TRANSMIT_FOLLOWUP = 7;
     69     private static final int CB_EV_DATA_PATH_REQUEST = 8;
     70     private static final int CB_EV_DATA_PATH_CONFIRM = 9;
     71     private static final int CB_EV_DATA_PATH_TERMINATED = 10;
     72 
     73     private SparseIntArray mCallbackCounter = new SparseIntArray();
     74 
     75     private void incrementCbCount(int callbackId) {
     76         mCallbackCounter.put(callbackId, mCallbackCounter.get(callbackId) + 1);
     77     }
     78 
     79     /**
     80      * Interpreter of adb shell command 'adb shell wifiaware native_cb ...'.
     81      *
     82      * @return -1 if parameter not recognized or invalid value, 0 otherwise.
     83      */
     84     @Override
     85     public int onCommand(ShellCommand parentShell) {
     86         final PrintWriter pwe = parentShell.getErrPrintWriter();
     87         final PrintWriter pwo = parentShell.getOutPrintWriter();
     88 
     89         String subCmd = parentShell.getNextArgRequired();
     90         if (VDBG) Log.v(TAG, "onCommand: subCmd='" + subCmd + "'");
     91         switch (subCmd) {
     92             case "get_cb_count": {
     93                 String option = parentShell.getNextOption();
     94                 Log.v(TAG, "option='" + option + "'");
     95                 boolean reset = false;
     96                 if (option != null) {
     97                     if ("--reset".equals(option)) {
     98                         reset = true;
     99                     } else {
    100                         pwe.println("Unknown option to 'get_cb_count'");
    101                         return -1;
    102                     }
    103                 }
    104 
    105                 JSONObject j = new JSONObject();
    106                 try {
    107                     for (int i = 0; i < mCallbackCounter.size(); ++i) {
    108                         j.put(Integer.toString(mCallbackCounter.keyAt(i)),
    109                                 mCallbackCounter.valueAt(i));
    110                     }
    111                 } catch (JSONException e) {
    112                     Log.e(TAG, "onCommand: get_cb_count e=" + e);
    113                 }
    114                 pwo.println(j.toString());
    115                 if (reset) {
    116                     mCallbackCounter.clear();
    117                 }
    118                 return 0;
    119             }
    120             default:
    121                 pwe.println("Unknown 'wifiaware native_cb <cmd>'");
    122         }
    123 
    124         return -1;
    125     }
    126 
    127     @Override
    128     public void onReset() {
    129         // NOP (onReset is intended for configuration reset - not data reset)
    130     }
    131 
    132     @Override
    133     public void onHelp(String command, ShellCommand parentShell) {
    134         final PrintWriter pw = parentShell.getOutPrintWriter();
    135 
    136         pw.println("  " + command);
    137         pw.println("    get_cb_count [--reset]: gets the number of callbacks (and optionally reset "
    138                 + "count)");
    139     }
    140 
    141     @Override
    142     public void notifyCapabilitiesResponse(short id, WifiNanStatus status,
    143             NanCapabilities capabilities) {
    144         if (VDBG) {
    145             Log.v(TAG, "notifyCapabilitiesResponse: id=" + id + ", status=" + statusString(status)
    146                     + ", capabilities=" + capabilities);
    147         }
    148 
    149         if (status.status == NanStatusType.SUCCESS) {
    150             Capabilities frameworkCapabilities = new Capabilities();
    151             frameworkCapabilities.maxConcurrentAwareClusters = capabilities.maxConcurrentClusters;
    152             frameworkCapabilities.maxPublishes = capabilities.maxPublishes;
    153             frameworkCapabilities.maxSubscribes = capabilities.maxSubscribes;
    154             frameworkCapabilities.maxServiceNameLen = capabilities.maxServiceNameLen;
    155             frameworkCapabilities.maxMatchFilterLen = capabilities.maxMatchFilterLen;
    156             frameworkCapabilities.maxTotalMatchFilterLen = capabilities.maxTotalMatchFilterLen;
    157             frameworkCapabilities.maxServiceSpecificInfoLen =
    158                     capabilities.maxServiceSpecificInfoLen;
    159             frameworkCapabilities.maxExtendedServiceSpecificInfoLen =
    160                     capabilities.maxExtendedServiceSpecificInfoLen;
    161             frameworkCapabilities.maxNdiInterfaces = capabilities.maxNdiInterfaces;
    162             frameworkCapabilities.maxNdpSessions = capabilities.maxNdpSessions;
    163             frameworkCapabilities.maxAppInfoLen = capabilities.maxAppInfoLen;
    164             frameworkCapabilities.maxQueuedTransmitMessages =
    165                     capabilities.maxQueuedTransmitFollowupMsgs;
    166             frameworkCapabilities.maxSubscribeInterfaceAddresses =
    167                     capabilities.maxSubscribeInterfaceAddresses;
    168             frameworkCapabilities.supportedCipherSuites = capabilities.supportedCipherSuites;
    169 
    170             mWifiAwareStateManager.onCapabilitiesUpdateResponse(id, frameworkCapabilities);
    171         } else {
    172             Log.e(TAG, "notifyCapabilitiesResponse: error code=" + status.status + " ("
    173                     + status.description + ")");
    174         }
    175     }
    176 
    177     @Override
    178     public void notifyEnableResponse(short id, WifiNanStatus status) {
    179         if (VDBG) Log.v(TAG, "notifyEnableResponse: id=" + id + ", status=" + statusString(status));
    180 
    181         if (status.status == NanStatusType.ALREADY_ENABLED) {
    182             Log.wtf(TAG, "notifyEnableResponse: id=" + id + ", already enabled!?");
    183         }
    184 
    185         if (status.status == NanStatusType.SUCCESS
    186                 || status.status == NanStatusType.ALREADY_ENABLED) {
    187             mWifiAwareStateManager.onConfigSuccessResponse(id);
    188         } else {
    189             mWifiAwareStateManager.onConfigFailedResponse(id, status.status);
    190         }
    191     }
    192 
    193     @Override
    194     public void notifyConfigResponse(short id, WifiNanStatus status) {
    195         if (VDBG) Log.v(TAG, "notifyConfigResponse: id=" + id + ", status=" + statusString(status));
    196 
    197         if (status.status == NanStatusType.SUCCESS) {
    198             mWifiAwareStateManager.onConfigSuccessResponse(id);
    199         } else {
    200             mWifiAwareStateManager.onConfigFailedResponse(id, status.status);
    201         }
    202     }
    203 
    204     @Override
    205     public void notifyDisableResponse(short id, WifiNanStatus status) {
    206         if (VDBG) {
    207             Log.v(TAG, "notifyDisableResponse: id=" + id + ", status=" + statusString(status));
    208         }
    209 
    210         if (status.status != NanStatusType.SUCCESS) {
    211             Log.e(TAG, "notifyDisableResponse: failure - code=" + status.status + " ("
    212                     + status.description + ")");
    213         }
    214         mWifiAwareStateManager.onDisableResponse(id, status.status);
    215     }
    216 
    217     @Override
    218     public void notifyStartPublishResponse(short id, WifiNanStatus status, byte publishId) {
    219         if (VDBG) {
    220             Log.v(TAG, "notifyStartPublishResponse: id=" + id + ", status=" + statusString(status)
    221                     + ", publishId=" + publishId);
    222         }
    223 
    224         if (status.status == NanStatusType.SUCCESS) {
    225             mWifiAwareStateManager.onSessionConfigSuccessResponse(id, true, publishId);
    226         } else {
    227             mWifiAwareStateManager.onSessionConfigFailResponse(id, true, status.status);
    228         }
    229     }
    230 
    231     @Override
    232     public void notifyStopPublishResponse(short id, WifiNanStatus status) {
    233         if (VDBG) {
    234             Log.v(TAG, "notifyStopPublishResponse: id=" + id + ", status=" + statusString(status));
    235         }
    236 
    237         if (status.status == NanStatusType.SUCCESS) {
    238             // NOP
    239         } else {
    240             Log.e(TAG, "notifyStopPublishResponse: failure - code=" + status.status + " ("
    241                     + status.description + ")");
    242         }
    243     }
    244 
    245     @Override
    246     public void notifyStartSubscribeResponse(short id, WifiNanStatus status, byte subscribeId) {
    247         if (VDBG) {
    248             Log.v(TAG, "notifyStartSubscribeResponse: id=" + id + ", status=" + statusString(status)
    249                     + ", subscribeId=" + subscribeId);
    250         }
    251 
    252         if (status.status == NanStatusType.SUCCESS) {
    253             mWifiAwareStateManager.onSessionConfigSuccessResponse(id, false, subscribeId);
    254         } else {
    255             mWifiAwareStateManager.onSessionConfigFailResponse(id, false, status.status);
    256         }
    257     }
    258 
    259     @Override
    260     public void notifyStopSubscribeResponse(short id, WifiNanStatus status) {
    261         if (VDBG) {
    262             Log.v(TAG, "notifyStopSubscribeResponse: id=" + id + ", status="
    263                     + statusString(status));
    264         }
    265 
    266         if (status.status == NanStatusType.SUCCESS) {
    267             // NOP
    268         } else {
    269             Log.e(TAG, "notifyStopSubscribeResponse: failure - code=" + status.status + " ("
    270                     + status.description + ")");
    271         }
    272     }
    273 
    274     @Override
    275     public void notifyTransmitFollowupResponse(short id, WifiNanStatus status) {
    276         if (VDBG) {
    277             Log.v(TAG, "notifyTransmitFollowupResponse: id=" + id + ", status="
    278                     + statusString(status));
    279         }
    280 
    281         if (status.status == NanStatusType.SUCCESS) {
    282             mWifiAwareStateManager.onMessageSendQueuedSuccessResponse(id);
    283         } else {
    284             mWifiAwareStateManager.onMessageSendQueuedFailResponse(id, status.status);
    285         }
    286     }
    287 
    288     @Override
    289     public void notifyCreateDataInterfaceResponse(short id, WifiNanStatus status) {
    290         if (VDBG) {
    291             Log.v(TAG, "notifyCreateDataInterfaceResponse: id=" + id + ", status="
    292                     + statusString(status));
    293         }
    294 
    295         mWifiAwareStateManager.onCreateDataPathInterfaceResponse(id,
    296                 status.status == NanStatusType.SUCCESS, status.status);
    297     }
    298 
    299     @Override
    300     public void notifyDeleteDataInterfaceResponse(short id, WifiNanStatus status) {
    301         if (VDBG) {
    302             Log.v(TAG, "notifyDeleteDataInterfaceResponse: id=" + id + ", status="
    303                     + statusString(status));
    304         }
    305 
    306         mWifiAwareStateManager.onDeleteDataPathInterfaceResponse(id,
    307                 status.status == NanStatusType.SUCCESS, status.status);
    308     }
    309 
    310     @Override
    311     public void notifyInitiateDataPathResponse(short id, WifiNanStatus status,
    312             int ndpInstanceId) {
    313         if (VDBG) {
    314             Log.v(TAG, "notifyInitiateDataPathResponse: id=" + id + ", status="
    315                     + statusString(status) + ", ndpInstanceId=" + ndpInstanceId);
    316         }
    317 
    318         if (status.status == NanStatusType.SUCCESS) {
    319             mWifiAwareStateManager.onInitiateDataPathResponseSuccess(id, ndpInstanceId);
    320         } else {
    321             mWifiAwareStateManager.onInitiateDataPathResponseFail(id, status.status);
    322         }
    323     }
    324 
    325     @Override
    326     public void notifyRespondToDataPathIndicationResponse(short id, WifiNanStatus status) {
    327         if (VDBG) {
    328             Log.v(TAG, "notifyRespondToDataPathIndicationResponse: id=" + id
    329                     + ", status=" + statusString(status));
    330         }
    331 
    332         mWifiAwareStateManager.onRespondToDataPathSetupRequestResponse(id,
    333                 status.status == NanStatusType.SUCCESS, status.status);
    334     }
    335 
    336     @Override
    337     public void notifyTerminateDataPathResponse(short id, WifiNanStatus status) {
    338         if (VDBG) {
    339             Log.v(TAG, "notifyTerminateDataPathResponse: id=" + id + ", status="
    340                     + statusString(status));
    341         }
    342 
    343         mWifiAwareStateManager.onEndDataPathResponse(id, status.status == NanStatusType.SUCCESS,
    344                 status.status);
    345     }
    346 
    347     @Override
    348     public void eventClusterEvent(NanClusterEventInd event) {
    349         if (VDBG) {
    350             Log.v(TAG, "eventClusterEvent: eventType=" + event.eventType + ", addr="
    351                     + String.valueOf(HexEncoding.encode(event.addr)));
    352         }
    353         incrementCbCount(CB_EV_CLUSTER);
    354 
    355         if (event.eventType == NanClusterEventType.DISCOVERY_MAC_ADDRESS_CHANGED) {
    356             mWifiAwareStateManager.onInterfaceAddressChangeNotification(event.addr);
    357         } else if (event.eventType == NanClusterEventType.STARTED_CLUSTER) {
    358             mWifiAwareStateManager.onClusterChangeNotification(
    359                     WifiAwareClientState.CLUSTER_CHANGE_EVENT_STARTED, event.addr);
    360         } else if (event.eventType == NanClusterEventType.JOINED_CLUSTER) {
    361             mWifiAwareStateManager.onClusterChangeNotification(
    362                     WifiAwareClientState.CLUSTER_CHANGE_EVENT_JOINED, event.addr);
    363         } else {
    364             Log.e(TAG, "eventClusterEvent: invalid eventType=" + event.eventType);
    365         }
    366     }
    367 
    368     @Override
    369     public void eventDisabled(WifiNanStatus status) {
    370         if (VDBG) Log.v(TAG, "eventDisabled: status=" + statusString(status));
    371         incrementCbCount(CB_EV_DISABLED);
    372 
    373         mWifiAwareStateManager.onAwareDownNotification(status.status);
    374     }
    375 
    376     @Override
    377     public void eventPublishTerminated(byte sessionId, WifiNanStatus status) {
    378         if (VDBG) {
    379             Log.v(TAG, "eventPublishTerminated: sessionId=" + sessionId + ", status="
    380                     + statusString(status));
    381         }
    382         incrementCbCount(CB_EV_PUBLISH_TERMINATED);
    383 
    384         mWifiAwareStateManager.onSessionTerminatedNotification(sessionId, status.status, true);
    385     }
    386 
    387     @Override
    388     public void eventSubscribeTerminated(byte sessionId, WifiNanStatus status) {
    389         if (VDBG) {
    390             Log.v(TAG, "eventSubscribeTerminated: sessionId=" + sessionId + ", status="
    391                     + statusString(status));
    392         }
    393         incrementCbCount(CB_EV_SUBSCRIBE_TERMINATED);
    394 
    395         mWifiAwareStateManager.onSessionTerminatedNotification(sessionId, status.status, false);
    396     }
    397 
    398     @Override
    399     public void eventMatch(NanMatchInd event) {
    400         if (VDBG) {
    401             Log.v(TAG, "eventMatch: discoverySessionId=" + event.discoverySessionId + ", peerId="
    402                     + event.peerId + ", addr=" + String.valueOf(HexEncoding.encode(event.addr))
    403                     + ", serviceSpecificInfo=" + Arrays.toString(
    404                     convertArrayListToNativeByteArray(event.serviceSpecificInfo)) + ", ssi.size()="
    405                     + (event.serviceSpecificInfo == null ? 0 : event.serviceSpecificInfo.size())
    406                     + ", matchFilter=" + Arrays.toString(
    407                     convertArrayListToNativeByteArray(event.matchFilter)) + ", mf.size()=" + (
    408                     event.matchFilter == null ? 0 : event.matchFilter.size()));
    409         }
    410         incrementCbCount(CB_EV_MATCH);
    411 
    412         mWifiAwareStateManager.onMatchNotification(event.discoverySessionId, event.peerId,
    413                 event.addr, convertArrayListToNativeByteArray(event.serviceSpecificInfo),
    414                 convertArrayListToNativeByteArray(event.matchFilter));
    415     }
    416 
    417     @Override
    418     public void eventMatchExpired(byte discoverySessionId, int peerId) {
    419         if (VDBG) {
    420             Log.v(TAG, "eventMatchExpired: discoverySessionId=" + discoverySessionId
    421                     + ", peerId=" + peerId);
    422         }
    423         incrementCbCount(CB_EV_MATCH_EXPIRED);
    424 
    425         // NOP
    426     }
    427 
    428     @Override
    429     public void eventFollowupReceived(NanFollowupReceivedInd event) {
    430         if (VDBG) {
    431             Log.v(TAG, "eventFollowupReceived: discoverySessionId=" + event.discoverySessionId
    432                     + ", peerId=" + event.peerId + ", addr=" + String.valueOf(
    433                     HexEncoding.encode(event.addr)) + ", serviceSpecificInfo=" + Arrays.toString(
    434                     convertArrayListToNativeByteArray(event.serviceSpecificInfo)) + ", ssi.size()="
    435                     + (event.serviceSpecificInfo == null ? 0 : event.serviceSpecificInfo.size()));
    436         }
    437         incrementCbCount(CB_EV_FOLLOWUP_RECEIVED);
    438 
    439         mWifiAwareStateManager.onMessageReceivedNotification(event.discoverySessionId, event.peerId,
    440                 event.addr, convertArrayListToNativeByteArray(event.serviceSpecificInfo));
    441     }
    442 
    443     @Override
    444     public void eventTransmitFollowup(short id, WifiNanStatus status) {
    445         if (VDBG) {
    446             Log.v(TAG, "eventTransmitFollowup: id=" + id + ", status=" + statusString(status));
    447         }
    448         incrementCbCount(CB_EV_TRANSMIT_FOLLOWUP);
    449 
    450         if (status.status == NanStatusType.SUCCESS) {
    451             mWifiAwareStateManager.onMessageSendSuccessNotification(id);
    452         } else {
    453             mWifiAwareStateManager.onMessageSendFailNotification(id, status.status);
    454         }
    455     }
    456 
    457     @Override
    458     public void eventDataPathRequest(NanDataPathRequestInd event) {
    459         if (VDBG) {
    460             Log.v(TAG, "eventDataPathRequest: discoverySessionId=" + event.discoverySessionId
    461                     + ", peerDiscMacAddr=" + String.valueOf(
    462                     HexEncoding.encode(event.peerDiscMacAddr)) + ", ndpInstanceId="
    463                     + event.ndpInstanceId);
    464         }
    465         incrementCbCount(CB_EV_DATA_PATH_REQUEST);
    466 
    467         mWifiAwareStateManager.onDataPathRequestNotification(event.discoverySessionId,
    468                 event.peerDiscMacAddr, event.ndpInstanceId);
    469     }
    470 
    471     @Override
    472     public void eventDataPathConfirm(NanDataPathConfirmInd event) {
    473         if (VDBG) {
    474             Log.v(TAG, "onDataPathConfirm: ndpInstanceId=" + event.ndpInstanceId
    475                     + ", peerNdiMacAddr=" + String.valueOf(HexEncoding.encode(event.peerNdiMacAddr))
    476                     + ", dataPathSetupSuccess=" + event.dataPathSetupSuccess + ", reason="
    477                     + event.status.status);
    478         }
    479         incrementCbCount(CB_EV_DATA_PATH_CONFIRM);
    480 
    481         mWifiAwareStateManager.onDataPathConfirmNotification(event.ndpInstanceId,
    482                 event.peerNdiMacAddr, event.dataPathSetupSuccess, event.status.status,
    483                 convertArrayListToNativeByteArray(event.appInfo));
    484     }
    485 
    486     @Override
    487     public void eventDataPathTerminated(int ndpInstanceId) {
    488         if (VDBG) Log.v(TAG, "eventDataPathTerminated: ndpInstanceId=" + ndpInstanceId);
    489         incrementCbCount(CB_EV_DATA_PATH_TERMINATED);
    490 
    491         mWifiAwareStateManager.onDataPathEndNotification(ndpInstanceId);
    492     }
    493 
    494     /**
    495      * Dump the internal state of the class.
    496      */
    497     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    498         pw.println("WifiAwareNativeCallback:");
    499         pw.println("  mCallbackCounter: " + mCallbackCounter);
    500     }
    501 
    502 
    503     // utilities
    504 
    505     /**
    506      * Converts an ArrayList<Byte> to a byte[].
    507      *
    508      * @param from The input ArrayList<Byte></Byte> to convert from.
    509      *
    510      * @return A newly allocated byte[].
    511      */
    512     private byte[] convertArrayListToNativeByteArray(ArrayList<Byte> from) {
    513         if (from == null) {
    514             return null;
    515         }
    516 
    517         byte[] to = new byte[from.size()];
    518         for (int i = 0; i < from.size(); ++i) {
    519             to[i] = from.get(i);
    520         }
    521         return to;
    522     }
    523 
    524     private static String statusString(WifiNanStatus status) {
    525         if (status == null) {
    526             return "status=null";
    527         }
    528         StringBuilder sb = new StringBuilder();
    529         sb.append(status.status).append(" (").append(status.description).append(")");
    530         return sb.toString();
    531     }
    532 }
    533