diff options
11 files changed, 202 insertions, 417 deletions
diff --git a/wifi/java/android/net/wifi/aware/ConfigRequest.java b/wifi/java/android/net/wifi/aware/ConfigRequest.java index 4aacbae6272f..4b21b15d4994 100644 --- a/wifi/java/android/net/wifi/aware/ConfigRequest.java +++ b/wifi/java/android/net/wifi/aware/ConfigRequest.java @@ -22,7 +22,7 @@ import android.os.Parcelable; /** * Defines a request object to configure a Wi-Fi Aware network. Built using * {@link ConfigRequest.Builder}. Configuration is requested using - * {@link WifiAwareManager#attach(android.os.Handler, WifiAwareAttachCallback)}. + * {@link WifiAwareManager#attach(WifiAwareAttachCallback, android.os.Handler)}. * Note that the actual achieved configuration may be different from the * requested configuration - since different applications may request different * configurations. diff --git a/wifi/java/android/net/wifi/aware/LvBufferUtils.java b/wifi/java/android/net/wifi/aware/LvBufferUtils.java deleted file mode 100644 index 3265243e28d6..000000000000 --- a/wifi/java/android/net/wifi/aware/LvBufferUtils.java +++ /dev/null @@ -1,340 +0,0 @@ -/* - * 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 android.net.wifi.aware; - -import android.annotation.Nullable; - -import libcore.io.Memory; - -import java.nio.ByteOrder; -import java.util.Iterator; - -/** - * Utility class to construct and parse byte arrays using the LV format - - * Length/Value format. The utilities accept a configuration of the size of - * the Length field. - * - * @hide PROPOSED_AWARE_API - */ -public class LvBufferUtils { - private LvBufferUtils() { - // no reason to ever create this class - } - - /** - * Utility class to construct byte arrays using the LV format - Length/Value. - * <p> - * A constructor is created specifying the size of the Length (L) field. - * <p> - * The byte array is either provided (using - * {@link LvBufferUtils.LvConstructor#wrap(byte[])}) or allocated (using - * {@link LvBufferUtils.LvConstructor#allocate(int)}). - * <p> - * Values are added to the structure using the {@code LvConstructor.put*()} - * methods. - * <p> - * The final byte array is obtained using {@link LvBufferUtils.LvConstructor#getArray()}. - */ - public static class LvConstructor { - private TlvBufferUtils.TlvConstructor mTlvImpl; - - /** - * Define a LV constructor with the specified size of the Length (L) field. - * - * @param lengthSize Number of bytes used for the Length (L) field. - * Values of 1 or 2 bytes are allowed. - */ - public LvConstructor(int lengthSize) { - mTlvImpl = new TlvBufferUtils.TlvConstructor(0, lengthSize); - } - - /** - * Set the byte array to be used to construct the LV. - * - * @param array Byte array to be formatted. - * @return The constructor to facilitate chaining - * {@code ctr.putXXX(..).putXXX(..)}. - */ - public LvBufferUtils.LvConstructor wrap(@Nullable byte[] array) { - mTlvImpl.wrap(array); - return this; - } - - /** - * Allocates a new byte array to be used ot construct a LV. - * - * @param capacity The size of the byte array to be allocated. - * @return The constructor to facilitate chaining - * {@code ctr.putXXX(..).putXXX(..)}. - */ - public LvBufferUtils.LvConstructor allocate(int capacity) { - mTlvImpl.allocate(capacity); - return this; - } - - /** - * Copies a byte into the LV array. - * - * @param b The byte to be inserted into the structure. - * @return The constructor to facilitate chaining - * {@code ctr.putXXX(..).putXXX(..)}. - */ - public LvBufferUtils.LvConstructor putByte(byte b) { - mTlvImpl.putByte(0, b); - return this; - } - - /** - * Copies a byte array into the LV. - * - * @param array The array to be copied into the LV structure. - * @param offset Start copying from the array at the specified offset. - * @param length Copy the specified number (length) of bytes from the - * array. - * @return The constructor to facilitate chaining - * {@code ctr.putXXX(..).putXXX(..)}. - */ - public LvBufferUtils.LvConstructor putByteArray(@Nullable byte[] array, int offset, - int length) { - mTlvImpl.putByteArray(0, array, offset, length); - return this; - } - - /** - * Copies a byte array into the LV. - * - * @param array The array to be copied (in full) into the LV structure. - * @return The constructor to facilitate chaining - * {@code ctr.putXXX(..).putXXX(..)}. - */ - public LvBufferUtils.LvConstructor putByteArray(int type, @Nullable byte[] array) { - return putByteArray(array, 0, (array == null) ? 0 : array.length); - } - - /** - * Places a zero length element (i.e. Length field = 0) into the LV. - * - * @return The constructor to facilitate chaining - * {@code ctr.putXXX(..).putXXX(..)}. - */ - public LvBufferUtils.LvConstructor putZeroLengthElement() { - mTlvImpl.putZeroLengthElement(0); - return this; - } - - /** - * Copies short into the LV. - * - * @param data The short to be inserted into the structure. - * @return The constructor to facilitate chaining - * {@code ctr.putXXX(..).putXXX(..)}. - */ - public LvBufferUtils.LvConstructor putShort(short data) { - mTlvImpl.putShort(0, data); - return this; - } - - /** - * Copies integer into the LV. - * - * @param data The integer to be inserted into the structure. - * @return The constructor to facilitate chaining - * {@code ctr.putXXX(..).putXXX(..)}. - */ - public LvBufferUtils.LvConstructor putInt(int data) { - mTlvImpl.putInt(0, data); - return this; - } - - /** - * Copies a String's byte representation into the LV. - * - * @param data The string whose bytes are to be inserted into the - * structure. - * @return The constructor to facilitate chaining - * {@code ctr.putXXX(..).putXXX(..)}. - */ - public LvBufferUtils.LvConstructor putString(@Nullable String data) { - mTlvImpl.putString(0, data); - return this; - } - - /** - * Returns the constructed LV formatted byte-array. This array is a copy of the wrapped - * or allocated array - truncated to just the significant bytes - i.e. those written into - * the LV. - * - * @return The byte array containing the LV formatted structure. - */ - public byte[] getArray() { - return mTlvImpl.getArray(); - } - } - - /** - * Utility class used when iterating over an LV formatted byte-array. Use - * {@link LvBufferUtils.LvIterable} to iterate over array. A {@link LvBufferUtils.LvElement} - * represents each entry in a LV formatted byte-array. - */ - public static class LvElement { - /** - * The Length (L) field of the current LV element. - */ - public int length; - - /** - * The Value (V) field - a raw byte array representing the current LV - * element where the entry starts at {@link LvBufferUtils.LvElement#offset}. - */ - public byte[] refArray; - - /** - * The offset to be used into {@link LvBufferUtils.LvElement#refArray} to access the - * raw data representing the current LV element. - */ - public int offset; - - private LvElement(int length, @Nullable byte[] refArray, int offset) { - this.length = length; - this.refArray = refArray; - this.offset = offset; - } - - /** - * Utility function to return a byte representation of a LV element of - * length 1. Note: an attempt to call this function on a LV item whose - * {@link LvBufferUtils.LvElement#length} is != 1 will result in an exception. - * - * @return byte representation of current LV element. - */ - public byte getByte() { - if (length != 1) { - throw new IllegalArgumentException( - "Accesing a byte from a LV element of length " + length); - } - return refArray[offset]; - } - - /** - * Utility function to return a short representation of a LV element of - * length 2. Note: an attempt to call this function on a LV item whose - * {@link LvBufferUtils.LvElement#length} is != 2 will result in an exception. - * - * @return short representation of current LV element. - */ - public short getShort() { - if (length != 2) { - throw new IllegalArgumentException( - "Accesing a short from a LV element of length " + length); - } - return Memory.peekShort(refArray, offset, ByteOrder.BIG_ENDIAN); - } - - /** - * Utility function to return an integer representation of a LV element - * of length 4. Note: an attempt to call this function on a LV item - * whose {@link LvBufferUtils.LvElement#length} is != 4 will result in an exception. - * - * @return integer representation of current LV element. - */ - public int getInt() { - if (length != 4) { - throw new IllegalArgumentException( - "Accesing an int from a LV element of length " + length); - } - return Memory.peekInt(refArray, offset, ByteOrder.BIG_ENDIAN); - } - - /** - * Utility function to return a String representation of a LV element. - * - * @return String representation of the current LV element. - */ - public String getString() { - return new String(refArray, offset, length); - } - } - - /** - * Utility class to iterate over a LV formatted byte-array. - */ - public static class LvIterable implements Iterable<LvBufferUtils.LvElement> { - private final TlvBufferUtils.TlvIterable mTlvIterable; - - /** - * Constructs an LvIterable object - specifying the format of the LV - * (the size of the Length field), and the byte array whose data is to be parsed. - * - * @param lengthSize Number of bytes sued for the Length (L) field. - * Values values are 1 or 2 bytes. - * @param array The LV formatted byte-array to parse. - */ - public LvIterable(int lengthSize, @Nullable byte[] array) { - mTlvIterable = new TlvBufferUtils.TlvIterable(0, lengthSize, array); - } - - /** - * Prints out a parsed representation of the LV-formatted byte array. - * Whenever possible bytes, shorts, and integer are printed out (for - * fields whose length is 1, 2, or 4 respectively). - */ - @Override - public String toString() { - return mTlvIterable.toString(); - } - - /** - * Returns an iterator to step through a LV formatted byte-array. The - * individual elements returned by the iterator are {@link LvBufferUtils.LvElement}. - */ - @Override - public Iterator<LvBufferUtils.LvElement> iterator() { - return new Iterator<LvBufferUtils.LvElement>() { - private Iterator<TlvBufferUtils.TlvElement> mTlvIterator = mTlvIterable.iterator(); - - @Override - public boolean hasNext() { - return mTlvIterator.hasNext(); - } - - @Override - public LvBufferUtils.LvElement next() { - TlvBufferUtils.TlvElement tlvE = mTlvIterator.next(); - - return new LvElement(tlvE.length, tlvE.refArray, tlvE.offset); - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - }; - } - } - - /** - * Validates that a LV array is constructed correctly. I.e. that its specified Length - * fields correctly fill the specified length (and do not overshoot). - * - * @param array The LV array to verify. - * @param lengthSize The size (in bytes) of the length field. Valid values are 1 or 2. - * @return A boolean indicating whether the array is valid (true) or invalid (false). - */ - public static boolean isValid(@Nullable byte[] array, int lengthSize) { - return TlvBufferUtils.isValid(array, 0, lengthSize); - } -} diff --git a/wifi/java/android/net/wifi/aware/PublishConfig.java b/wifi/java/android/net/wifi/aware/PublishConfig.java index ba493a024a13..3925bd71ab9e 100644 --- a/wifi/java/android/net/wifi/aware/PublishConfig.java +++ b/wifi/java/android/net/wifi/aware/PublishConfig.java @@ -28,6 +28,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.nio.charset.StandardCharsets; import java.util.Arrays; +import java.util.List; /** * Defines the configuration of a Aware publish session. Built using @@ -84,7 +85,8 @@ public final class PublishConfig implements Parcelable { /** @hide */ public final boolean mEnableTerminateNotification; - private PublishConfig(byte[] serviceName, byte[] serviceSpecificInfo, byte[] matchFilter, + /** @hide */ + public PublishConfig(byte[] serviceName, byte[] serviceSpecificInfo, byte[] matchFilter, int publishType, int publichCount, int ttlSec, boolean enableTerminateNotification) { mServiceName = serviceName; mServiceSpecificInfo = serviceSpecificInfo; @@ -99,9 +101,9 @@ public final class PublishConfig implements Parcelable { public String toString() { return "PublishConfig [mServiceName='" + mServiceName + ", mServiceSpecificInfo='" + ( (mServiceSpecificInfo == null) ? "null" : HexEncoding.encode(mServiceSpecificInfo)) - + ", mTxFilter=" + (new LvBufferUtils.LvIterable(1, mMatchFilter)).toString() - + ", mPublishType=" + mPublishType + ", mPublishCount=" + mPublishCount - + ", mTtlSec=" + mTtlSec + ", mEnableTerminateNotification=" + + ", mMatchFilter=" + (new TlvBufferUtils.TlvIterable(0, 1, + mMatchFilter)).toString() + ", mPublishType=" + mPublishType + ", mPublishCount=" + + mPublishCount + ", mTtlSec=" + mTtlSec + ", mEnableTerminateNotification=" + mEnableTerminateNotification + "]"; } @@ -186,7 +188,7 @@ public final class PublishConfig implements Parcelable { throws IllegalArgumentException { WifiAwareUtils.validateServiceName(mServiceName); - if (!LvBufferUtils.isValid(mMatchFilter, 1)) { + if (!TlvBufferUtils.isValid(mMatchFilter, 0, 1)) { throw new IllegalArgumentException( "Invalid txFilter configuration - LV fields do not match up to length"); } @@ -281,18 +283,17 @@ public final class PublishConfig implements Parcelable { * The match filter for a publish session. Used to determine whether a service * discovery occurred - in addition to relying on the service name. * <p> - * Format is an LV byte array: a single byte Length field followed by L bytes (the value of - * the Length field) of a value blob. - * <p> * Optional. Empty by default. * - * @param matchFilter The byte-array containing the LV formatted match filter. + * @param matchFilter A list of match filter entries (each of which is an arbitrary byte + * array). * * @return The builder to facilitate chaining * {@code builder.setXXX(..).setXXX(..)}. */ - public Builder setMatchFilter(@Nullable byte[] matchFilter) { - mMatchFilter = matchFilter; + public Builder setMatchFilter(@Nullable List<byte[]> matchFilter) { + mMatchFilter = new TlvBufferUtils.TlvConstructor(0, 1).allocateAndPut( + matchFilter).getArray(); return this; } diff --git a/wifi/java/android/net/wifi/aware/SubscribeConfig.java b/wifi/java/android/net/wifi/aware/SubscribeConfig.java index 5e14f8f761e0..bf35445ff88a 100644 --- a/wifi/java/android/net/wifi/aware/SubscribeConfig.java +++ b/wifi/java/android/net/wifi/aware/SubscribeConfig.java @@ -28,6 +28,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.nio.charset.StandardCharsets; import java.util.Arrays; +import java.util.List; /** * Defines the configuration of a Aware subscribe session. Built using @@ -106,7 +107,8 @@ public final class SubscribeConfig implements Parcelable { /** @hide */ public final boolean mEnableTerminateNotification; - private SubscribeConfig(byte[] serviceName, byte[] serviceSpecificInfo, byte[] matchFilter, + /** @hide */ + public SubscribeConfig(byte[] serviceName, byte[] serviceSpecificInfo, byte[] matchFilter, int subscribeType, int publichCount, int ttlSec, int matchStyle, boolean enableTerminateNotification) { mServiceName = serviceName; @@ -123,10 +125,11 @@ public final class SubscribeConfig implements Parcelable { public String toString() { return "SubscribeConfig [mServiceName='" + mServiceName + ", mServiceSpecificInfo='" + ( (mServiceSpecificInfo == null) ? "null" : HexEncoding.encode(mServiceSpecificInfo)) - + ", mMatchFilter=" + (new LvBufferUtils.LvIterable(1, mMatchFilter)).toString() - + ", mSubscribeType=" + mSubscribeType + ", mSubscribeCount=" + mSubscribeCount - + ", mTtlSec=" + mTtlSec + ", mMatchType=" + mMatchStyle - + ", mEnableTerminateNotification=" + mEnableTerminateNotification + "]"; + + ", mMatchFilter=" + (new TlvBufferUtils.TlvIterable(0, 1, + mMatchFilter)).toString() + ", mSubscribeType=" + mSubscribeType + + ", mSubscribeCount=" + mSubscribeCount + ", mTtlSec=" + mTtlSec + ", mMatchType=" + + mMatchStyle + ", mEnableTerminateNotification=" + mEnableTerminateNotification + + "]"; } @Override @@ -213,7 +216,7 @@ public final class SubscribeConfig implements Parcelable { throws IllegalArgumentException { WifiAwareUtils.validateServiceName(mServiceName); - if (!LvBufferUtils.isValid(mMatchFilter, 1)) { + if (!TlvBufferUtils.isValid(mMatchFilter, 0, 1)) { throw new IllegalArgumentException( "Invalid matchFilter configuration - LV fields do not match up to length"); } @@ -313,18 +316,17 @@ public final class SubscribeConfig implements Parcelable { * The match filter for a subscribe session. Used to determine whether a service * discovery occurred - in addition to relying on the service name. * <p> - * Format is an LV byte array: a single byte Length field followed by L bytes (the value of - * the Length field) of a value blob. - * <p> * Optional. Empty by default. * - * @param matchFilter The byte-array containing the LV formatted match filter. + * @param matchFilter A list of match filter entries (each of which is an arbitrary byte + * array). * * @return The builder to facilitate chaining * {@code builder.setXXX(..).setXXX(..)}. */ - public Builder setMatchFilter(@Nullable byte[] matchFilter) { - mMatchFilter = matchFilter; + public Builder setMatchFilter(@Nullable List<byte[]> matchFilter) { + mMatchFilter = new TlvBufferUtils.TlvConstructor(0, 1).allocateAndPut( + matchFilter).getArray(); return this; } diff --git a/wifi/java/android/net/wifi/aware/TlvBufferUtils.java b/wifi/java/android/net/wifi/aware/TlvBufferUtils.java index 56c90692f1b8..29f10e932e48 100644 --- a/wifi/java/android/net/wifi/aware/TlvBufferUtils.java +++ b/wifi/java/android/net/wifi/aware/TlvBufferUtils.java @@ -22,8 +22,10 @@ import libcore.io.Memory; import java.nio.BufferOverflowException; import java.nio.ByteOrder; +import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; +import java.util.List; import java.util.NoSuchElementException; /** @@ -32,7 +34,7 @@ import java.util.NoSuchElementException; * the Type field and the Length field. A Type field size of 0 is allowed - * allowing usage for LV (no T) array formats. * - * @hide PROPOSED_AWARE_API + * @hide */ public class TlvBufferUtils { private TlvBufferUtils() { @@ -111,6 +113,31 @@ public class TlvBufferUtils { } /** + * Creates a TLV array (of the previously specified Type and Length sizes) from the input + * list. Allocates an array matching the contents (and required Type and Length + * fields), copies the contents, and set the Length fields. The Type field is set to 0. + * + * @param list A list of fields to be added to the TLV buffer. + * @return The constructor of the TLV. + */ + public TlvConstructor allocateAndPut(@Nullable List<byte[]> list) { + if (list != null) { + int size = 0; + for (byte[] field : list) { + size += mTypeSize + mLengthSize; + if (field != null) { + size += field.length; + } + } + allocate(size); + for (byte[] field : list) { + putByteArray(0, field); + } + } + return this; + } + + /** * Copies a byte into the TLV with the indicated type. For an LV * formatted structure (i.e. typeLength=0 in {@link TlvConstructor * TlvConstructor(int, int)} ) the type field is ignored. @@ -319,6 +346,10 @@ public class TlvBufferUtils { this.length = length; this.refArray = refArray; this.offset = offset; + + if (offset + length > refArray.length) { + throw new BufferOverflowException(); + } } /** @@ -393,7 +424,7 @@ public class TlvBufferUtils { * @param typeSize Number of bytes used for the Type (T) field. Valid * values are 0 (i.e. indicating the format is LV rather than * TLV), 1, and 2 bytes. - * @param lengthSize Number of bytes sued for the Length (L) field. + * @param lengthSize Number of bytes used for the Length (L) field. * Values values are 1 or 2 bytes. * @param array The TLV formatted byte-array to parse. */ @@ -450,6 +481,18 @@ public class TlvBufferUtils { } /** + * Returns a List with the raw contents (no types) of the iterator. + */ + public List<byte[]> toList() { + List<byte[]> list = new ArrayList<>(); + for (TlvElement tlv : this) { + list.add(Arrays.copyOfRange(tlv.refArray, tlv.offset, tlv.offset + tlv.length)); + } + + return list; + } + + /** * Returns an iterator to step through a TLV formatted byte-array. The * individual elements returned by the iterator are {@link TlvElement}. */ diff --git a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java b/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java index 072ccab1eb96..95d128d8e514 100644 --- a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java +++ b/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java @@ -69,8 +69,9 @@ public class WifiAwareCharacteristics implements Parcelable { /** * Returns the maximum length of byte array that can be used to specify a Aware match filter. - * Restricts the parameters of the {@link PublishConfig.Builder#setMatchFilter(byte[])} and - * {@link SubscribeConfig.Builder#setMatchFilter(byte[])}. + * Restricts the parameters of the + * {@link PublishConfig.Builder#setMatchFilter(java.util.List<byte[]>)} and + * {@link SubscribeConfig.Builder#setMatchFilter(java.util.List<byte[]>)}. * * @return A positive integer, maximum legngth of byte array for Aware discovery match filter. */ diff --git a/wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java b/wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java index 01e77dadcba3..451d8a594cc5 100644 --- a/wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java +++ b/wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java @@ -140,7 +140,7 @@ public class WifiAwareDiscoveryBaseSession { * Sends a message to the specified destination. Aware messages are transmitted in the context * of a discovery session - executed subsequent to a publish/subscribe * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle, - * byte[], byte[])} event. + * byte[], java.util.List<byte[]>)} event. * <p> * Aware messages are not guaranteed delivery. Callbacks on * {@link WifiAwareDiscoverySessionCallback} indicate message was transmitted successfully, @@ -154,7 +154,7 @@ public class WifiAwareDiscoveryBaseSession { * * @param peerHandle The peer's handle for the message. Must be a result of an * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle, - * byte[], byte[])} or + * byte[], java.util.List<byte[]>)} or * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle, * byte[])} events. * @param messageId An arbitrary integer used by the caller to identify the message. The same @@ -187,7 +187,7 @@ public class WifiAwareDiscoveryBaseSession { * Sends a message to the specified destination. Aware messages are transmitted in the context * of a discovery session - executed subsequent to a publish/subscribe * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle, - * byte[], byte[])} event. + * byte[], java.util.List<byte[]>)} event. * <p> * Aware messages are not guaranteed delivery. Callbacks on * {@link WifiAwareDiscoverySessionCallback} indicate message was transmitted successfully, @@ -203,7 +203,7 @@ public class WifiAwareDiscoveryBaseSession { * * @param peerHandle The peer's handle for the message. Must be a result of an * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle, - * byte[], byte[])} or + * byte[], java.util.List<byte[]>)} or * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle, * byte[])} events. * @param messageId An arbitrary integer used by the caller to identify the message. The same @@ -220,7 +220,7 @@ public class WifiAwareDiscoveryBaseSession { /** * Start a ranging operation with the specified peers. The peer IDs are obtained from an * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle, - * byte[], byte[])} or + * byte[], java.util.List<byte[]>)} or * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle, * byte[])} operation - can * only range devices which are part of an ongoing discovery session. @@ -266,7 +266,7 @@ public class WifiAwareDiscoveryBaseSession { * * @param peerHandle The peer's handle obtained through * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle, - * byte[], byte[])} or + * byte[], java.util.List<byte[]>)} or * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle, * byte[])}. On a RESPONDER this value is used to gate the acceptance of a connection request * from only that peer. A RESPONDER may specified a null - indicating that diff --git a/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java b/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java index 6331c9c726c9..fdf0d013334d 100644 --- a/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java +++ b/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java @@ -21,6 +21,7 @@ import android.annotation.NonNull; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.List; /** * Base class for Aware session events callbacks. Should be extended by @@ -130,11 +131,10 @@ public class WifiAwareDiscoverySessionCallback { * @param serviceSpecificInfo The service specific information (arbitrary * byte array) provided by the peer as part of its discovery * configuration. - * @param matchFilter The filter (Tx on advertiser and Rx on listener) which - * resulted in this service discovery. + * @param matchFilter The filter which resulted in this service discovery. */ public void onServiceDiscovered(WifiAwareManager.PeerHandle peerHandle, - byte[] serviceSpecificInfo, byte[] matchFilter) { + byte[] serviceSpecificInfo, List<byte[]> matchFilter) { /* empty */ } diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java index cc247047758e..029794dfa380 100644 --- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java +++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java @@ -45,7 +45,9 @@ import org.json.JSONObject; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; +import java.nio.BufferOverflowException; import java.util.Arrays; +import java.util.List; /** * This class provides the primary API for managing Wi-Fi Aware operations: @@ -874,12 +876,22 @@ public class WifiAwareManager { case CALLBACK_SESSION_TERMINATED: onProxySessionTerminated(msg.arg1); break; - case CALLBACK_MATCH: - mOriginalCallback.onServiceDiscovered( - new PeerHandle(msg.arg1), + case CALLBACK_MATCH: { + List<byte[]> matchFilter = null; + byte[] arg = msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE2); + try { + matchFilter = new TlvBufferUtils.TlvIterable(0, 1, arg).toList(); + } catch (BufferOverflowException e) { + matchFilter = null; + Log.e(TAG, "onServiceDiscovered: invalid match filter byte array '" + + new String(HexEncoding.encode(arg)) + + "' - cannot be parsed: e=" + e); + } + mOriginalCallback.onServiceDiscovered(new PeerHandle(msg.arg1), msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE), - msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE2)); + matchFilter); break; + } case CALLBACK_MESSAGE_SEND_SUCCESS: mOriginalCallback.onMessageSendSucceeded(msg.arg1); break; @@ -966,7 +978,7 @@ public class WifiAwareManager { @Override public void onMessageReceived(int peerId, byte[] message) { if (VDBG) { - Log.v(TAG, "onMessageReceived: peerId='" + peerId); + Log.v(TAG, "onMessageReceived: peerId=" + peerId); } Message msg = mHandler.obtainMessage(CALLBACK_MESSAGE_RECEIVED); diff --git a/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java b/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java index 4b6957bfa3f6..15641abd11f9 100644 --- a/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java +++ b/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java @@ -24,6 +24,10 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ErrorCollector; +import java.nio.BufferOverflowException; +import java.util.ArrayList; +import java.util.List; + /** * Unit test harness for TlvBufferUtils class. */ @@ -47,9 +51,9 @@ public class TlvBufferUtilsTest { collector.checkThat("tlv11-correct-construction", tlv11.getArray(), equalTo(new byte[]{0, 1, 2, 2, 3, 0, 1, 2})); - LvBufferUtils.LvConstructor tlv01 = new LvBufferUtils.LvConstructor(1); + TlvBufferUtils.TlvConstructor tlv01 = new TlvBufferUtils.TlvConstructor(0, 1); tlv01.allocate(15); - tlv01.putByte((byte) 2); + tlv01.putByte(0, (byte) 2); tlv01.putByteArray(2, new byte[] { 0, 1, 2 }); @@ -60,10 +64,63 @@ public class TlvBufferUtilsTest { TlvBufferUtils.isValid(tlv11.getArray(), 1, 1), equalTo(true)); collector.checkThat("tlv01-valid", - LvBufferUtils.isValid(tlv01.getArray(), 1), + TlvBufferUtils.isValid(tlv01.getArray(), 0, 1), equalTo(true)); } + /** + * Verify that can build a valid TLV from a List of byte[]. + */ + @Test + public void testTlvListOperations() { + byte[] entry1 = { 1, 2, 3 }; + byte[] entry2 = { 4, 5 }; + byte[] entry3 = new byte[0]; + List<byte[]> data = new ArrayList<>(); + data.add(entry1); + data.add(entry2); + data.add(entry3); + data.add(null); // zero-length should work + + TlvBufferUtils.TlvConstructor tlv01 = new TlvBufferUtils.TlvConstructor(0, 1); + tlv01.allocateAndPut(data); + byte[] tlvData = tlv01.getArray(); + List<byte[]> parsedList = new TlvBufferUtils.TlvIterable(0, 1, tlvData).toList(); + + collector.checkThat("tlvData-correct-length", tlvData.length, + equalTo(entry1.length + 1 + entry2.length + 1 + entry3.length + 1 + 1)); + collector.checkThat("parsedList-correct-length", parsedList.size(), equalTo(4)); + collector.checkThat("parsedList-entry1", parsedList.get(0), equalTo(entry1)); + collector.checkThat("parsedList-entry2", parsedList.get(1), equalTo(entry2)); + collector.checkThat("parsedList-entry3", parsedList.get(2), equalTo(entry3)); + collector.checkThat("parsedList-entry4", parsedList.get(3), equalTo(new byte[0])); + } + + /** + * Verify that can parse a (correctly formatted) byte array to a list. + */ + @Test + public void testTlvParseToList() { + byte[] validTlv01 = { 0, 1, 55, 2, 33, 66, 0 }; + + List<byte[]> parsedList = new TlvBufferUtils.TlvIterable(0, 1, validTlv01).toList(); + + collector.checkThat("parsedList-entry1", parsedList.get(0), equalTo(new byte[0])); + collector.checkThat("parsedList-entry2", parsedList.get(1), equalTo(new byte[] { 55 })); + collector.checkThat("parsedList-entry3", parsedList.get(2), equalTo(new byte[] { 33, 66 })); + collector.checkThat("parsedList-entry4", parsedList.get(3), equalTo(new byte[0])); + } + + /** + * Verify that an exception is thrown when trying to parse an invalid array. + */ + @Test(expected = BufferOverflowException.class) + public void testTlvParseToListError() { + byte[] invalidTlv01 = { 0, 1, 55, 2, 55, 66, 3 }; // bad data + + List<byte[]> data = new TlvBufferUtils.TlvIterable(0, 1, invalidTlv01).toList(); + } + @Test public void testTlvIterate() { final String ascii = "ABC"; @@ -137,7 +194,7 @@ public class TlvBufferUtilsTest { TlvBufferUtils.isValid(tlv22.getArray(), 2, 2), equalTo(true)); collector.checkThat("tlv02-valid", - LvBufferUtils.isValid(tlv02.getArray(), 2), + TlvBufferUtils.isValid(tlv02.getArray(), 0, 2), equalTo(true)); } @@ -211,15 +268,15 @@ public class TlvBufferUtilsTest { */ @Test public void testTlvInvalidByteArray() { - LvBufferUtils.LvConstructor tlv01 = new LvBufferUtils.LvConstructor(1); + TlvBufferUtils.TlvConstructor tlv01 = new TlvBufferUtils.TlvConstructor(0, 1); tlv01.allocate(15); - tlv01.putByte((byte) 2); + tlv01.putByte(0, (byte) 2); tlv01.putByteArray(2, new byte[]{0, 1, 2}); byte[] array = tlv01.getArray(); array[0] = 10; collector.checkThat("tlv01-invalid", - LvBufferUtils.isValid(array, 1), equalTo(false)); + TlvBufferUtils.isValid(array, 0, 1), equalTo(false)); } } diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java index e1613106751e..24c0127cb11b 100644 --- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java +++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java @@ -49,6 +49,8 @@ import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.List; + /** * Unit test harness for WifiAwareManager class. */ @@ -276,7 +278,7 @@ public class WifiAwareManagerTest { final PublishConfig publishConfig = new PublishConfig.Builder().build(); final WifiAwareManager.PeerHandle peerHandle = new WifiAwareManager.PeerHandle(873); final String string1 = "hey from here..."; - final String string2 = "some other arbitrary string..."; + final byte[] matchFilter = { 1, 12, 2, 31, 32 }; final int messageId = 2123; final int reason = AWARE_STATUS_ERROR; @@ -292,6 +294,8 @@ public class WifiAwareManagerTest { .forClass(WifiAwarePublishDiscoverySession.class); ArgumentCaptor<WifiAwareManager.PeerHandle> peerIdCaptor = ArgumentCaptor.forClass( WifiAwareManager.PeerHandle.class); + ArgumentCaptor<List<byte[]>> matchFilterCaptor = ArgumentCaptor.forClass( + (Class) List.class); // (0) connect + success mDut.attach(mMockLooperHandler, configRequest, mockCallback, null); @@ -314,8 +318,7 @@ public class WifiAwareManagerTest { // (3) ... publishSession.getValue().sendMessage(peerHandle, messageId, string1.getBytes()); - sessionProxyCallback.getValue().onMatch(peerHandle.peerId, string1.getBytes(), - string2.getBytes()); + sessionProxyCallback.getValue().onMatch(peerHandle.peerId, string1.getBytes(), matchFilter); sessionProxyCallback.getValue().onMessageReceived(peerHandle.peerId, string1.getBytes()); sessionProxyCallback.getValue().onMessageSendFail(messageId, reason); sessionProxyCallback.getValue().onMessageSendSuccess(messageId); @@ -324,13 +327,22 @@ public class WifiAwareManagerTest { inOrder.verify(mockAwareService).sendMessage(eq(clientId), eq(sessionId), eq(peerHandle.peerId), eq(string1.getBytes()), eq(messageId), eq(0)); inOrder.verify(mockSessionCallback).onServiceDiscovered(peerIdCaptor.capture(), - eq(string1.getBytes()), eq(string2.getBytes())); - assertEquals(((WifiAwareManager.PeerHandle) peerIdCaptor.getValue()).peerId, - peerHandle.peerId); + eq(string1.getBytes()), + matchFilterCaptor.capture()); + + // note: need to capture/compare elements since the Mockito eq() is a shallow comparator + List<byte[]> parsedMatchFilter = new TlvBufferUtils.TlvIterable(0, 1, matchFilter).toList(); + collector.checkThat("match-filter-size", parsedMatchFilter.size(), + equalTo(matchFilterCaptor.getValue().size())); + collector.checkThat("match-filter-entry0", parsedMatchFilter.get(0), + equalTo(matchFilterCaptor.getValue().get(0))); + collector.checkThat("match-filter-entry1", parsedMatchFilter.get(1), + equalTo(matchFilterCaptor.getValue().get(1))); + + assertEquals(peerIdCaptor.getValue().peerId, peerHandle.peerId); inOrder.verify(mockSessionCallback).onMessageReceived(peerIdCaptor.capture(), eq(string1.getBytes())); - assertEquals(((WifiAwareManager.PeerHandle) peerIdCaptor.getValue()).peerId, - peerHandle.peerId); + assertEquals(peerIdCaptor.getValue().peerId, peerHandle.peerId); inOrder.verify(mockSessionCallback).onMessageSendFailed(eq(messageId)); inOrder.verify(mockSessionCallback).onMessageSendSucceeded(eq(messageId)); @@ -418,7 +430,7 @@ public class WifiAwareManagerTest { final SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build(); final WifiAwareManager.PeerHandle peerHandle = new WifiAwareManager.PeerHandle(873); final String string1 = "hey from here..."; - final String string2 = "some other arbitrary string..."; + final byte[] matchFilter = { 1, 12, 3, 31, 32 }; // bad data! final int messageId = 2123; final int reason = AWARE_STATUS_ERROR; @@ -456,8 +468,7 @@ public class WifiAwareManagerTest { // (3) ... subscribeSession.getValue().sendMessage(peerHandle, messageId, string1.getBytes()); - sessionProxyCallback.getValue().onMatch(peerHandle.peerId, string1.getBytes(), - string2.getBytes()); + sessionProxyCallback.getValue().onMatch(peerHandle.peerId, string1.getBytes(), matchFilter); sessionProxyCallback.getValue().onMessageReceived(peerHandle.peerId, string1.getBytes()); sessionProxyCallback.getValue().onMessageSendFail(messageId, reason); sessionProxyCallback.getValue().onMessageSendSuccess(messageId); @@ -466,13 +477,11 @@ public class WifiAwareManagerTest { inOrder.verify(mockAwareService).sendMessage(eq(clientId), eq(sessionId), eq(peerHandle.peerId), eq(string1.getBytes()), eq(messageId), eq(0)); inOrder.verify(mockSessionCallback).onServiceDiscovered(peerIdCaptor.capture(), - eq(string1.getBytes()), eq(string2.getBytes())); - assertEquals(((WifiAwareManager.PeerHandle) peerIdCaptor.getValue()).peerId, - peerHandle.peerId); + eq(string1.getBytes()), (List<byte[]>) isNull()); + assertEquals((peerIdCaptor.getValue()).peerId, peerHandle.peerId); inOrder.verify(mockSessionCallback).onMessageReceived(peerIdCaptor.capture(), eq(string1.getBytes())); - assertEquals(((WifiAwareManager.PeerHandle) peerIdCaptor.getValue()).peerId, - peerHandle.peerId); + assertEquals((peerIdCaptor.getValue()).peerId, peerHandle.peerId); inOrder.verify(mockSessionCallback).onMessageSendFailed(eq(messageId)); inOrder.verify(mockSessionCallback).onMessageSendSucceeded(eq(messageId)); @@ -676,8 +685,7 @@ public class WifiAwareManagerTest { public void testSubscribeConfigBuilder() { final String serviceName = "some_service_or_other"; final String serviceSpecificInfo = "long arbitrary string with some info"; - final byte[] matchFilter = { - 0, 1, 16, 1, 22 }; + final byte[] matchFilter = { 1, 16, 1, 22 }; final int subscribeType = SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE; final int subscribeCount = 10; final int subscribeTtl = 15; @@ -685,7 +693,8 @@ public class WifiAwareManagerTest { final boolean enableTerminateNotification = false; SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName(serviceName) - .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter(matchFilter) + .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter( + new TlvBufferUtils.TlvIterable(0, 1, matchFilter).toList()) .setSubscribeType(subscribeType) .setSubscribeCount(subscribeCount).setTtlSec(subscribeTtl).setMatchStyle(matchStyle) .setTerminateNotificationEnabled(enableTerminateNotification).build(); @@ -709,8 +718,7 @@ public class WifiAwareManagerTest { public void testSubscribeConfigParcel() { final String serviceName = "some_service_or_other"; final String serviceSpecificInfo = "long arbitrary string with some info"; - final byte[] matchFilter = { - 0, 1, 16, 1, 22 }; + final byte[] matchFilter = { 1, 16, 1, 22 }; final int subscribeType = SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE; final int subscribeCount = 10; final int subscribeTtl = 15; @@ -718,7 +726,8 @@ public class WifiAwareManagerTest { final boolean enableTerminateNotification = true; SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName(serviceName) - .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter(matchFilter) + .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter( + new TlvBufferUtils.TlvIterable(0, 1, matchFilter).toList()) .setSubscribeType(subscribeType) .setSubscribeCount(subscribeCount).setTtlSec(subscribeTtl).setMatchStyle(matchStyle) .setTerminateNotificationEnabled(enableTerminateNotification).build(); @@ -780,15 +789,15 @@ public class WifiAwareManagerTest { public void testPublishConfigBuilder() { final String serviceName = "some_service_or_other"; final String serviceSpecificInfo = "long arbitrary string with some info"; - final byte[] matchFilter = { - 0, 1, 16, 1, 22 }; + final byte[] matchFilter = { 1, 16, 1, 22 }; final int publishType = PublishConfig.PUBLISH_TYPE_SOLICITED; final int publishCount = 10; final int publishTtl = 15; final boolean enableTerminateNotification = false; PublishConfig publishConfig = new PublishConfig.Builder().setServiceName(serviceName) - .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter(matchFilter) + .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter( + new TlvBufferUtils.TlvIterable(0, 1, matchFilter).toList()) .setPublishType(publishType) .setPublishCount(publishCount).setTtlSec(publishTtl) .setTerminateNotificationEnabled(enableTerminateNotification).build(); @@ -809,15 +818,15 @@ public class WifiAwareManagerTest { public void testPublishConfigParcel() { final String serviceName = "some_service_or_other"; final String serviceSpecificInfo = "long arbitrary string with some info"; - final byte[] matchFilter = { - 0, 1, 16, 1, 22 }; + final byte[] matchFilter = { 1, 16, 1, 22 }; final int publishType = PublishConfig.PUBLISH_TYPE_SOLICITED; final int publishCount = 10; final int publishTtl = 15; final boolean enableTerminateNotification = false; PublishConfig publishConfig = new PublishConfig.Builder().setServiceName(serviceName) - .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter(matchFilter) + .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter( + new TlvBufferUtils.TlvIterable(0, 1, matchFilter).toList()) .setPublishType(publishType) .setPublishCount(publishCount).setTtlSec(publishTtl) .setTerminateNotificationEnabled(enableTerminateNotification).build(); |