/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.wifi.aware; import android.hardware.wifi.V1_0.NanStatusType; import android.net.wifi.aware.IWifiAwareDiscoverySessionCallback; import android.net.wifi.aware.PublishConfig; import android.net.wifi.aware.SubscribeConfig; import android.os.RemoteException; import android.util.Log; import android.util.SparseArray; import libcore.util.HexEncoding; import java.io.FileDescriptor; import java.io.PrintWriter; /** * Manages the state of a single Aware discovery session (publish or subscribe). * Primary state consists of a callback through which session callbacks are * executed as well as state related to currently active discovery sessions: * publish/subscribe ID, and MAC address caching (hiding) from clients. */ public class WifiAwareDiscoverySessionState { private static final String TAG = "WifiAwareDiscSessState"; private static final boolean DBG = false; private static final boolean VDBG = false; // STOPSHIP if true private final WifiAwareNativeApi mWifiAwareNativeApi; private int mSessionId; private int mPubSubId; private IWifiAwareDiscoverySessionCallback mCallback; private boolean mIsPublishSession; private final SparseArray mMacByRequestorInstanceId = new SparseArray<>(); public WifiAwareDiscoverySessionState(WifiAwareNativeApi wifiAwareNativeApi, int sessionId, int pubSubId, IWifiAwareDiscoverySessionCallback callback, boolean isPublishSession) { mWifiAwareNativeApi = wifiAwareNativeApi; mSessionId = sessionId; mPubSubId = pubSubId; mCallback = callback; mIsPublishSession = isPublishSession; } public int getSessionId() { return mSessionId; } public int getPubSubId() { return mPubSubId; } public boolean isPublishSession() { return mIsPublishSession; } public IWifiAwareDiscoverySessionCallback getCallback() { return mCallback; } /** * Return the MAC address (String) of the specified peer ID - or a null if no such address is * registered. */ public String getMac(int peerId, String sep) { String mac = mMacByRequestorInstanceId.get(peerId); if (mac != null && sep != null && !sep.isEmpty()) { mac = new StringBuilder(mac).insert(10, sep).insert(8, sep).insert(6, sep) .insert(4, sep).insert(2, sep).toString(); } return mac; } /** * Destroy the current discovery session - stops publishing or subscribing * if currently active. */ public void terminate() { mCallback = null; if (mIsPublishSession) { mWifiAwareNativeApi.stopPublish((short) 0, mPubSubId); } else { mWifiAwareNativeApi.stopSubscribe((short) 0, mPubSubId); } } /** * Indicates whether the publish/subscribe ID (a HAL ID) corresponds to this * session. * * @param pubSubId The publish/subscribe HAL ID to be tested. * @return true if corresponds to this session, false otherwise. */ public boolean isPubSubIdSession(int pubSubId) { return mPubSubId == pubSubId; } /** * Modify a publish discovery session. * * @param transactionId Transaction ID for the transaction - used in the * async callback to match with the original request. * @param config Configuration of the publish session. */ public boolean updatePublish(short transactionId, PublishConfig config) { if (!mIsPublishSession) { Log.e(TAG, "A SUBSCRIBE session is being used to publish"); try { mCallback.onSessionConfigFail(NanStatusType.INTERNAL_FAILURE); } catch (RemoteException e) { Log.e(TAG, "updatePublish: RemoteException=" + e); } return false; } boolean success = mWifiAwareNativeApi.publish(transactionId, mPubSubId, config); if (!success) { try { mCallback.onSessionConfigFail(NanStatusType.INTERNAL_FAILURE); } catch (RemoteException e) { Log.w(TAG, "updatePublish onSessionConfigFail(): RemoteException (FYI): " + e); } } return success; } /** * Modify a subscribe discovery session. * * @param transactionId Transaction ID for the transaction - used in the * async callback to match with the original request. * @param config Configuration of the subscribe session. */ public boolean updateSubscribe(short transactionId, SubscribeConfig config) { if (mIsPublishSession) { Log.e(TAG, "A PUBLISH session is being used to subscribe"); try { mCallback.onSessionConfigFail(NanStatusType.INTERNAL_FAILURE); } catch (RemoteException e) { Log.e(TAG, "updateSubscribe: RemoteException=" + e); } return false; } boolean success = mWifiAwareNativeApi.subscribe(transactionId, mPubSubId, config); if (!success) { try { mCallback.onSessionConfigFail(NanStatusType.INTERNAL_FAILURE); } catch (RemoteException e) { Log.w(TAG, "updateSubscribe onSessionConfigFail(): RemoteException (FYI): " + e); } } return success; } /** * Send a message to a peer which is part of a discovery session. * * @param transactionId Transaction ID for the transaction - used in the * async callback to match with the original request. * @param peerId ID of the peer. Obtained through previous communication (a * match indication). * @param message Message byte array to send to the peer. * @param messageId A message ID provided by caller to be used in any * callbacks related to the message (success/failure). */ public boolean sendMessage(short transactionId, int peerId, byte[] message, int messageId) { String peerMacStr = mMacByRequestorInstanceId.get(peerId); if (peerMacStr == null) { Log.e(TAG, "sendMessage: attempting to send a message to an address which didn't " + "match/contact us"); try { mCallback.onMessageSendFail(messageId, NanStatusType.INTERNAL_FAILURE); } catch (RemoteException e) { Log.e(TAG, "sendMessage: RemoteException=" + e); } return false; } byte[] peerMac = HexEncoding.decode(peerMacStr.toCharArray(), false); boolean success = mWifiAwareNativeApi.sendMessage(transactionId, mPubSubId, peerId, peerMac, message, messageId); if (!success) { try { mCallback.onMessageSendFail(messageId, NanStatusType.INTERNAL_FAILURE); } catch (RemoteException e) { Log.e(TAG, "sendMessage: RemoteException=" + e); } return false; } return success; } /** * Callback from HAL when a discovery occurs - i.e. when a match to an * active subscription request or to a solicited publish request occurs. * Propagates to client if registered. * * @param requestorInstanceId The ID used to identify the peer in this * matched session. * @param peerMac The MAC address of the peer. Never propagated to client * due to privacy concerns. * @param serviceSpecificInfo Information from the discovery advertisement * (usually not used in the match decisions). * @param matchFilter The filter from the discovery advertisement (which was * used in the match decision). */ public void onMatch(int requestorInstanceId, byte[] peerMac, byte[] serviceSpecificInfo, byte[] matchFilter) { String prevMac = mMacByRequestorInstanceId.get(requestorInstanceId); mMacByRequestorInstanceId.put(requestorInstanceId, new String(HexEncoding.encode(peerMac))); if (DBG) Log.d(TAG, "onMatch: previous peer MAC replaced - " + prevMac); try { mCallback.onMatch(requestorInstanceId, serviceSpecificInfo, matchFilter); } catch (RemoteException e) { Log.w(TAG, "onMatch: RemoteException (FYI): " + e); } } /** * Callback from HAL when a message is received from a peer in a discovery * session. Propagated to client if registered. * * @param requestorInstanceId An ID used to identify the peer. * @param peerMac The MAC address of the peer sending the message. This * information is never propagated to the client due to privacy * concerns. * @param message The received message. */ public void onMessageReceived(int requestorInstanceId, byte[] peerMac, byte[] message) { String prevMac = mMacByRequestorInstanceId.get(requestorInstanceId); mMacByRequestorInstanceId.put(requestorInstanceId, new String(HexEncoding.encode(peerMac))); if (DBG) { Log.d(TAG, "onMessageReceived: previous peer MAC replaced - " + prevMac); } try { mCallback.onMessageReceived(requestorInstanceId, message); } catch (RemoteException e) { Log.w(TAG, "onMessageReceived: RemoteException (FYI): " + e); } } /** * Dump the internal state of the class. */ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("AwareSessionState:"); pw.println(" mSessionId: " + mSessionId); pw.println(" mIsPublishSession: " + mIsPublishSession); pw.println(" mPubSubId: " + mPubSubId); pw.println(" mMacByRequestorInstanceId: [" + mMacByRequestorInstanceId + "]"); } }