Home | History | Annotate | Download | only in aware
      1 /*
      2  * Copyright (C) 2016 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.NanStatusType;
     20 import android.net.wifi.aware.IWifiAwareDiscoverySessionCallback;
     21 import android.net.wifi.aware.PublishConfig;
     22 import android.net.wifi.aware.SubscribeConfig;
     23 import android.os.RemoteException;
     24 import android.util.Log;
     25 import android.util.SparseArray;
     26 
     27 import libcore.util.HexEncoding;
     28 
     29 import java.io.FileDescriptor;
     30 import java.io.PrintWriter;
     31 import java.util.Arrays;
     32 
     33 /**
     34  * Manages the state of a single Aware discovery session (publish or subscribe).
     35  * Primary state consists of a callback through which session callbacks are
     36  * executed as well as state related to currently active discovery sessions:
     37  * publish/subscribe ID, and MAC address caching (hiding) from clients.
     38  */
     39 public class WifiAwareDiscoverySessionState {
     40     private static final String TAG = "WifiAwareDiscSessState";
     41     private static final boolean VDBG = false; // STOPSHIP if true
     42     /* package */ boolean mDbg = false;
     43 
     44     private static int sNextPeerIdToBeAllocated = 100; // used to create a unique peer ID
     45 
     46     private final WifiAwareNativeApi mWifiAwareNativeApi;
     47     private int mSessionId;
     48     private byte mPubSubId;
     49     private IWifiAwareDiscoverySessionCallback mCallback;
     50     private boolean mIsPublishSession;
     51     private boolean mIsRangingEnabled;
     52     private final long mCreationTime;
     53 
     54     static class PeerInfo {
     55         PeerInfo(int instanceId, byte[] mac) {
     56             mInstanceId = instanceId;
     57             mMac = mac;
     58         }
     59 
     60         int mInstanceId;
     61         byte[] mMac;
     62 
     63         @Override
     64         public String toString() {
     65             StringBuilder sb = new StringBuilder("instanceId [");
     66             sb.append(mInstanceId).append(", mac=").append(HexEncoding.encode(mMac)).append("]");
     67             return sb.toString();
     68         }
     69     }
     70 
     71     private final SparseArray<PeerInfo> mPeerInfoByRequestorInstanceId = new SparseArray<>();
     72 
     73     public WifiAwareDiscoverySessionState(WifiAwareNativeApi wifiAwareNativeApi, int sessionId,
     74             byte pubSubId, IWifiAwareDiscoverySessionCallback callback, boolean isPublishSession,
     75             boolean isRangingEnabled, long creationTime) {
     76         mWifiAwareNativeApi = wifiAwareNativeApi;
     77         mSessionId = sessionId;
     78         mPubSubId = pubSubId;
     79         mCallback = callback;
     80         mIsPublishSession = isPublishSession;
     81         mIsRangingEnabled = isRangingEnabled;
     82         mCreationTime = creationTime;
     83     }
     84 
     85     public int getSessionId() {
     86         return mSessionId;
     87     }
     88 
     89     public int getPubSubId() {
     90         return mPubSubId;
     91     }
     92 
     93     public boolean isPublishSession() {
     94         return mIsPublishSession;
     95     }
     96 
     97     public boolean isRangingEnabled() {
     98         return mIsRangingEnabled;
     99     }
    100 
    101     public long getCreationTime() {
    102         return mCreationTime;
    103     }
    104 
    105     public IWifiAwareDiscoverySessionCallback getCallback() {
    106         return mCallback;
    107     }
    108 
    109     /**
    110      * Return the peer information of the specified peer ID - or a null if no such peer ID is
    111      * registered.
    112      */
    113     public PeerInfo getPeerInfo(int peerId) {
    114         return mPeerInfoByRequestorInstanceId.get(peerId);
    115     }
    116 
    117     /**
    118      * Destroy the current discovery session - stops publishing or subscribing
    119      * if currently active.
    120      */
    121     public void terminate() {
    122         mCallback = null;
    123 
    124         if (mIsPublishSession) {
    125             mWifiAwareNativeApi.stopPublish((short) 0, mPubSubId);
    126         } else {
    127             mWifiAwareNativeApi.stopSubscribe((short) 0, mPubSubId);
    128         }
    129     }
    130 
    131     /**
    132      * Indicates whether the publish/subscribe ID (a HAL ID) corresponds to this
    133      * session.
    134      *
    135      * @param pubSubId The publish/subscribe HAL ID to be tested.
    136      * @return true if corresponds to this session, false otherwise.
    137      */
    138     public boolean isPubSubIdSession(int pubSubId) {
    139         return mPubSubId == pubSubId;
    140     }
    141 
    142     /**
    143      * Modify a publish discovery session.
    144      *
    145      * @param transactionId Transaction ID for the transaction - used in the
    146      *            async callback to match with the original request.
    147      * @param config Configuration of the publish session.
    148      */
    149     public boolean updatePublish(short transactionId, PublishConfig config) {
    150         if (!mIsPublishSession) {
    151             Log.e(TAG, "A SUBSCRIBE session is being used to publish");
    152             try {
    153                 mCallback.onSessionConfigFail(NanStatusType.INTERNAL_FAILURE);
    154             } catch (RemoteException e) {
    155                 Log.e(TAG, "updatePublish: RemoteException=" + e);
    156             }
    157             return false;
    158         }
    159 
    160         boolean success = mWifiAwareNativeApi.publish(transactionId, mPubSubId, config);
    161         if (!success) {
    162             try {
    163                 mCallback.onSessionConfigFail(NanStatusType.INTERNAL_FAILURE);
    164             } catch (RemoteException e) {
    165                 Log.w(TAG, "updatePublish onSessionConfigFail(): RemoteException (FYI): " + e);
    166             }
    167         }
    168 
    169         return success;
    170     }
    171 
    172     /**
    173      * Modify a subscribe discovery session.
    174      *
    175      * @param transactionId Transaction ID for the transaction - used in the
    176      *            async callback to match with the original request.
    177      * @param config Configuration of the subscribe session.
    178      */
    179     public boolean updateSubscribe(short transactionId, SubscribeConfig config) {
    180         if (mIsPublishSession) {
    181             Log.e(TAG, "A PUBLISH session is being used to subscribe");
    182             try {
    183                 mCallback.onSessionConfigFail(NanStatusType.INTERNAL_FAILURE);
    184             } catch (RemoteException e) {
    185                 Log.e(TAG, "updateSubscribe: RemoteException=" + e);
    186             }
    187             return false;
    188         }
    189 
    190         boolean success = mWifiAwareNativeApi.subscribe(transactionId, mPubSubId, config);
    191         if (!success) {
    192             try {
    193                 mCallback.onSessionConfigFail(NanStatusType.INTERNAL_FAILURE);
    194             } catch (RemoteException e) {
    195                 Log.w(TAG, "updateSubscribe onSessionConfigFail(): RemoteException (FYI): " + e);
    196             }
    197         }
    198 
    199         return success;
    200     }
    201 
    202     /**
    203      * Send a message to a peer which is part of a discovery session.
    204      *
    205      * @param transactionId Transaction ID for the transaction - used in the
    206      *            async callback to match with the original request.
    207      * @param peerId ID of the peer. Obtained through previous communication (a
    208      *            match indication).
    209      * @param message Message byte array to send to the peer.
    210      * @param messageId A message ID provided by caller to be used in any
    211      *            callbacks related to the message (success/failure).
    212      */
    213     public boolean sendMessage(short transactionId, int peerId, byte[] message, int messageId) {
    214         PeerInfo peerInfo = mPeerInfoByRequestorInstanceId.get(peerId);
    215         if (peerInfo == null) {
    216             Log.e(TAG, "sendMessage: attempting to send a message to an address which didn't "
    217                     + "match/contact us");
    218             try {
    219                 mCallback.onMessageSendFail(messageId, NanStatusType.INTERNAL_FAILURE);
    220             } catch (RemoteException e) {
    221                 Log.e(TAG, "sendMessage: RemoteException=" + e);
    222             }
    223             return false;
    224         }
    225 
    226         boolean success = mWifiAwareNativeApi.sendMessage(transactionId, mPubSubId,
    227                 peerInfo.mInstanceId, peerInfo.mMac, message, messageId);
    228         if (!success) {
    229             try {
    230                 mCallback.onMessageSendFail(messageId, NanStatusType.INTERNAL_FAILURE);
    231             } catch (RemoteException e) {
    232                 Log.e(TAG, "sendMessage: RemoteException=" + e);
    233             }
    234             return false;
    235         }
    236 
    237         return success;
    238     }
    239 
    240     /**
    241      * Callback from HAL when a discovery occurs - i.e. when a match to an
    242      * active subscription request or to a solicited publish request occurs.
    243      * Propagates to client if registered.
    244      *
    245      * @param requestorInstanceId The ID used to identify the peer in this
    246      *            matched session.
    247      * @param peerMac The MAC address of the peer. Never propagated to client
    248      *            due to privacy concerns.
    249      * @param serviceSpecificInfo Information from the discovery advertisement
    250      *            (usually not used in the match decisions).
    251      * @param matchFilter The filter from the discovery advertisement (which was
    252      *            used in the match decision).
    253      * @param rangingIndication Bit mask indicating the type of ranging event triggered.
    254      * @param rangeMm The range to the peer in mm (valid if rangingIndication specifies ingress
    255      *                or egress events - i.e. non-zero).
    256      */
    257     public void onMatch(int requestorInstanceId, byte[] peerMac, byte[] serviceSpecificInfo,
    258             byte[] matchFilter, int rangingIndication, int rangeMm) {
    259         int peerId = getPeerIdOrAddIfNew(requestorInstanceId, peerMac);
    260 
    261         try {
    262             if (rangingIndication == 0) {
    263                 mCallback.onMatch(peerId, serviceSpecificInfo, matchFilter);
    264             } else {
    265                 mCallback.onMatchWithDistance(peerId, serviceSpecificInfo, matchFilter, rangeMm);
    266             }
    267         } catch (RemoteException e) {
    268             Log.w(TAG, "onMatch: RemoteException (FYI): " + e);
    269         }
    270     }
    271 
    272     /**
    273      * Callback from HAL when a message is received from a peer in a discovery
    274      * session. Propagated to client if registered.
    275      *
    276      * @param requestorInstanceId An ID used to identify the peer.
    277      * @param peerMac The MAC address of the peer sending the message. This
    278      *            information is never propagated to the client due to privacy
    279      *            concerns.
    280      * @param message The received message.
    281      */
    282     public void onMessageReceived(int requestorInstanceId, byte[] peerMac, byte[] message) {
    283         int peerId = getPeerIdOrAddIfNew(requestorInstanceId, peerMac);
    284 
    285         try {
    286             mCallback.onMessageReceived(peerId, message);
    287         } catch (RemoteException e) {
    288             Log.w(TAG, "onMessageReceived: RemoteException (FYI): " + e);
    289         }
    290     }
    291 
    292     private int getPeerIdOrAddIfNew(int requestorInstanceId, byte[] peerMac) {
    293         for (int i = 0; i < mPeerInfoByRequestorInstanceId.size(); ++i) {
    294             PeerInfo peerInfo = mPeerInfoByRequestorInstanceId.valueAt(i);
    295             if (peerInfo.mInstanceId == requestorInstanceId && Arrays.equals(peerMac,
    296                     peerInfo.mMac)) {
    297                 return mPeerInfoByRequestorInstanceId.keyAt(i);
    298             }
    299         }
    300 
    301         int newPeerId = sNextPeerIdToBeAllocated++;
    302         PeerInfo newPeerInfo = new PeerInfo(requestorInstanceId, peerMac);
    303         mPeerInfoByRequestorInstanceId.put(newPeerId, newPeerInfo);
    304 
    305         if (VDBG) {
    306             Log.v(TAG, "New peer info: peerId=" + newPeerId + ", peerInfo=" + newPeerInfo);
    307         }
    308 
    309         return newPeerId;
    310     }
    311 
    312     /**
    313      * Dump the internal state of the class.
    314      */
    315     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    316         pw.println("AwareSessionState:");
    317         pw.println("  mSessionId: " + mSessionId);
    318         pw.println("  mIsPublishSession: " + mIsPublishSession);
    319         pw.println("  mPubSubId: " + mPubSubId);
    320         pw.println("  mPeerInfoByRequestorInstanceId: [" + mPeerInfoByRequestorInstanceId + "]");
    321     }
    322 }
    323