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