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