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