blob: bfd3e2c19c9be40235ee8dca656d1a96e1eeccb0 [file] [log] [blame]
/*
* 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.net.wifi.util.HexEncoding;
import android.os.RemoteException;
import android.util.Log;
import android.util.SparseArray;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Arrays;
/**
* 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 boolean mDbg = false;
private static int sNextPeerIdToBeAllocated = 100; // used to create a unique peer ID
private final WifiAwareNativeApi mWifiAwareNativeApi;
private int mSessionId;
private byte mPubSubId;
private IWifiAwareDiscoverySessionCallback mCallback;
private boolean mIsPublishSession;
private boolean mIsRangingEnabled;
private final long mCreationTime;
static class PeerInfo {
PeerInfo(int instanceId, byte[] mac) {
mInstanceId = instanceId;
mMac = mac;
}
int mInstanceId;
byte[] mMac;
@Override
public String toString() {
StringBuilder sb = new StringBuilder("instanceId [");
sb.append(mInstanceId).append(", mac=").append(HexEncoding.encode(mMac)).append("]");
return sb.toString();
}
}
private final SparseArray<PeerInfo> mPeerInfoByRequestorInstanceId = new SparseArray<>();
public WifiAwareDiscoverySessionState(WifiAwareNativeApi wifiAwareNativeApi, int sessionId,
byte pubSubId, IWifiAwareDiscoverySessionCallback callback, boolean isPublishSession,
boolean isRangingEnabled, long creationTime) {
mWifiAwareNativeApi = wifiAwareNativeApi;
mSessionId = sessionId;
mPubSubId = pubSubId;
mCallback = callback;
mIsPublishSession = isPublishSession;
mIsRangingEnabled = isRangingEnabled;
mCreationTime = creationTime;
}
/**
* Enable verbose logging.
*/
public void enableVerboseLogging(boolean verbose) {
mDbg = verbose;
}
public int getSessionId() {
return mSessionId;
}
public int getPubSubId() {
return mPubSubId;
}
public boolean isPublishSession() {
return mIsPublishSession;
}
public boolean isRangingEnabled() {
return mIsRangingEnabled;
}
public void setRangingEnabled(boolean enabled) {
mIsRangingEnabled = enabled;
}
public long getCreationTime() {
return mCreationTime;
}
public IWifiAwareDiscoverySessionCallback getCallback() {
return mCallback;
}
/**
* Return the peer information of the specified peer ID - or a null if no such peer ID is
* registered.
*/
public PeerInfo getPeerInfo(int peerId) {
return mPeerInfoByRequestorInstanceId.get(peerId);
}
/**
* 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) {
PeerInfo peerInfo = mPeerInfoByRequestorInstanceId.get(peerId);
if (peerInfo == 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;
}
boolean success = mWifiAwareNativeApi.sendMessage(transactionId, mPubSubId,
peerInfo.mInstanceId, peerInfo.mMac, 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).
* @param rangingIndication Bit mask indicating the type of ranging event triggered.
* @param rangeMm The range to the peer in mm (valid if rangingIndication specifies ingress
* or egress events - i.e. non-zero).
*/
public void onMatch(int requestorInstanceId, byte[] peerMac, byte[] serviceSpecificInfo,
byte[] matchFilter, int rangingIndication, int rangeMm) {
int peerId = getPeerIdOrAddIfNew(requestorInstanceId, peerMac);
try {
if (rangingIndication == 0) {
mCallback.onMatch(peerId, serviceSpecificInfo, matchFilter);
} else {
mCallback.onMatchWithDistance(peerId, serviceSpecificInfo, matchFilter, rangeMm);
}
} 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) {
int peerId = getPeerIdOrAddIfNew(requestorInstanceId, peerMac);
try {
mCallback.onMessageReceived(peerId, message);
} catch (RemoteException e) {
Log.w(TAG, "onMessageReceived: RemoteException (FYI): " + e);
}
}
private int getPeerIdOrAddIfNew(int requestorInstanceId, byte[] peerMac) {
for (int i = 0; i < mPeerInfoByRequestorInstanceId.size(); ++i) {
PeerInfo peerInfo = mPeerInfoByRequestorInstanceId.valueAt(i);
if (peerInfo.mInstanceId == requestorInstanceId && Arrays.equals(peerMac,
peerInfo.mMac)) {
return mPeerInfoByRequestorInstanceId.keyAt(i);
}
}
int newPeerId = sNextPeerIdToBeAllocated++;
PeerInfo newPeerInfo = new PeerInfo(requestorInstanceId, peerMac);
mPeerInfoByRequestorInstanceId.put(newPeerId, newPeerInfo);
if (mDbg) {
Log.v(TAG, "New peer info: peerId=" + newPeerId + ", peerInfo=" + newPeerInfo);
}
return newPeerId;
}
/**
* 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(" mPeerInfoByRequestorInstanceId: [" + mPeerInfoByRequestorInstanceId + "]");
}
}