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