WifiAwareDiscoverySessionState.java revision eddf3faabf426d18b7d3dff187ec91fe6a96665d
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
17package com.android.server.wifi.aware;
18
19import android.hardware.wifi.V1_0.NanStatusType;
20import android.net.wifi.aware.IWifiAwareDiscoverySessionCallback;
21import android.net.wifi.aware.PublishConfig;
22import android.net.wifi.aware.SubscribeConfig;
23import android.os.RemoteException;
24import android.util.Log;
25import android.util.SparseArray;
26
27import libcore.util.HexEncoding;
28
29import java.io.FileDescriptor;
30import java.io.PrintWriter;
31import 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 */
39public 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