WifiAwareDiscoverySessionState.java revision 5254a256676974e9db86fcb86b2f41af7d4a59f5
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;
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 */
38public 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        return mWifiAwareNativeApi.sendMessage(transactionId, mPubSubId, peerId, peerMac, message,
200                messageId);
201    }
202
203    /**
204     * Callback from HAL when a discovery occurs - i.e. when a match to an
205     * active subscription request or to a solicited publish request occurs.
206     * Propagates to client if registered.
207     *
208     * @param requestorInstanceId The ID used to identify the peer in this
209     *            matched session.
210     * @param peerMac The MAC address of the peer. Never propagated to client
211     *            due to privacy concerns.
212     * @param serviceSpecificInfo Information from the discovery advertisement
213     *            (usually not used in the match decisions).
214     * @param matchFilter The filter from the discovery advertisement (which was
215     *            used in the match decision).
216     */
217    public void onMatch(int requestorInstanceId, byte[] peerMac, byte[] serviceSpecificInfo,
218            byte[] matchFilter) {
219        String prevMac = mMacByRequestorInstanceId.get(requestorInstanceId);
220        mMacByRequestorInstanceId.put(requestorInstanceId, new String(HexEncoding.encode(peerMac)));
221
222        if (DBG) Log.d(TAG, "onMatch: previous peer MAC replaced - " + prevMac);
223
224        try {
225            mCallback.onMatch(requestorInstanceId, serviceSpecificInfo, matchFilter);
226        } catch (RemoteException e) {
227            Log.w(TAG, "onMatch: RemoteException (FYI): " + e);
228        }
229    }
230
231    /**
232     * Callback from HAL when a message is received from a peer in a discovery
233     * session. Propagated to client if registered.
234     *
235     * @param requestorInstanceId An ID used to identify the peer.
236     * @param peerMac The MAC address of the peer sending the message. This
237     *            information is never propagated to the client due to privacy
238     *            concerns.
239     * @param message The received message.
240     */
241    public void onMessageReceived(int requestorInstanceId, byte[] peerMac, byte[] message) {
242        String prevMac = mMacByRequestorInstanceId.get(requestorInstanceId);
243        mMacByRequestorInstanceId.put(requestorInstanceId, new String(HexEncoding.encode(peerMac)));
244
245        if (DBG) {
246            Log.d(TAG, "onMessageReceived: previous peer MAC replaced - " + prevMac);
247        }
248
249        try {
250            mCallback.onMessageReceived(requestorInstanceId, message);
251        } catch (RemoteException e) {
252            Log.w(TAG, "onMessageReceived: RemoteException (FYI): " + e);
253        }
254    }
255
256    /**
257     * Dump the internal state of the class.
258     */
259    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
260        pw.println("AwareSessionState:");
261        pw.println("  mSessionId: " + mSessionId);
262        pw.println("  mIsPublishSession: " + mIsPublishSession);
263        pw.println("  mPubSubId: " + mPubSubId);
264        pw.println("  mMacByRequestorInstanceId: [" + mMacByRequestorInstanceId + "]");
265    }
266}
267