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