--- /dev/null
+/*
+ * Copyright (C) 2017 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.net.NetworkSpecifier;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import libcore.util.HexEncoding;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.StringJoiner;
+
+/**
+ * A network specifier object used to represent the capabilities of an network agent. A collection
+ * of multiple WifiAwareNetworkSpecifier objects whose matching critiera (satisfiedBy) is an OR:
+ * a match on any of the network specifiers in the collection is a match.
+ *
+ * This class is not intended for use in network requests.
+ *
+ * @hide
+ */
+public class WifiAwareAgentNetworkSpecifier extends NetworkSpecifier implements Parcelable {
+ private static final String TAG = "WifiAwareAgentNs";
+
+ private static final boolean VDBG = false; // STOPSHIP if true
+
+ private Set<ByteArrayWrapper> mNetworkSpecifiers = new HashSet<>();
+ private MessageDigest mDigester;
+
+ public WifiAwareAgentNetworkSpecifier() {
+ // do nothing, already initialized to empty
+ }
+
+ public WifiAwareAgentNetworkSpecifier(WifiAwareNetworkSpecifier ns) {
+ initialize();
+ mNetworkSpecifiers.add(convert(ns));
+ }
+
+ public WifiAwareAgentNetworkSpecifier(WifiAwareNetworkSpecifier[] nss) {
+ initialize();
+ for (WifiAwareNetworkSpecifier ns : nss) {
+ mNetworkSpecifiers.add(convert(ns));
+ }
+ }
+
+ public boolean isEmpty() {
+ return mNetworkSpecifiers.isEmpty();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeArray(mNetworkSpecifiers.toArray());
+ }
+
+ public static final Creator<WifiAwareAgentNetworkSpecifier> CREATOR =
+ new Creator<WifiAwareAgentNetworkSpecifier>() {
+ @Override
+ public WifiAwareAgentNetworkSpecifier createFromParcel(Parcel in) {
+ WifiAwareAgentNetworkSpecifier agentNs = new WifiAwareAgentNetworkSpecifier();
+ Object[] objs = in.readArray(null);
+ for (Object obj : objs) {
+ agentNs.mNetworkSpecifiers.add((ByteArrayWrapper) obj);
+ }
+ return agentNs;
+ }
+
+ @Override
+ public WifiAwareAgentNetworkSpecifier[] newArray(int size) {
+ return new WifiAwareAgentNetworkSpecifier[size];
+ }
+ };
+
+ @Override
+ public int hashCode() {
+ return mNetworkSpecifiers.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof WifiAwareAgentNetworkSpecifier)) {
+ return false;
+ }
+ return mNetworkSpecifiers.equals(((WifiAwareAgentNetworkSpecifier) obj).mNetworkSpecifiers);
+ }
+
+ @Override
+ public String toString() {
+ StringJoiner sj = new StringJoiner(",");
+ for (ByteArrayWrapper baw: mNetworkSpecifiers) {
+ sj.add(baw.toString());
+ }
+ return sj.toString();
+ }
+
+ @Override
+ public boolean satisfiedBy(NetworkSpecifier other) {
+ if (!(other instanceof WifiAwareAgentNetworkSpecifier)) {
+ return false;
+ }
+ WifiAwareAgentNetworkSpecifier otherNs = (WifiAwareAgentNetworkSpecifier) other;
+
+ // called as old.satifiedBy(new): satisfied if old contained in new
+ for (ByteArrayWrapper baw: mNetworkSpecifiers) {
+ if (!otherNs.mNetworkSpecifiers.contains(baw)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public boolean satisfiesAwareNetworkSpecifier(WifiAwareNetworkSpecifier ns) {
+ if (VDBG) Log.v(TAG, "satisfiesAwareNetworkSpecifier: ns=" + ns);
+ ByteArrayWrapper nsBytes = convert(ns);
+ return mNetworkSpecifiers.contains(nsBytes);
+ }
+
+ @Override
+ public void assertValidFromUid(int requestorUid) {
+ throw new SecurityException(
+ "WifiAwareAgentNetworkSpecifier should not be used in network requests");
+ }
+
+ private void initialize() {
+ try {
+ mDigester = MessageDigest.getInstance("SHA-256");
+ } catch (NoSuchAlgorithmException e) {
+ Log.e(TAG, "Can not instantiate a SHA-256 digester!? Will match nothing.");
+ return;
+ }
+ }
+
+ private ByteArrayWrapper convert(WifiAwareNetworkSpecifier ns) {
+ if (mDigester == null) {
+ return null;
+ }
+
+ Parcel parcel = Parcel.obtain();
+ ns.writeToParcel(parcel, 0);
+ byte[] bytes = parcel.marshall();
+
+ mDigester.reset();
+ mDigester.update(bytes);
+ return new ByteArrayWrapper(mDigester.digest());
+ }
+
+ private static class ByteArrayWrapper implements Parcelable {
+ private byte[] mData;
+
+ ByteArrayWrapper(byte[] data) {
+ mData = data;
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(mData);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof ByteArrayWrapper)) {
+ return false;
+ }
+ return Arrays.equals(((ByteArrayWrapper) obj).mData, mData);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeBlob(mData);
+ }
+
+ public static final Creator<ByteArrayWrapper> CREATOR =
+ new Creator<ByteArrayWrapper>() {
+ @Override
+ public ByteArrayWrapper createFromParcel(Parcel in) {
+ return new ByteArrayWrapper(in.readBlob());
+ }
+
+ @Override
+ public ByteArrayWrapper[] newArray(int size) {
+ return new ByteArrayWrapper[size];
+ }
+ };
+
+ @Override
+ public String toString() {
+ return new String(HexEncoding.encode(mData));
+ }
+ }
+}
@Override
public boolean satisfiedBy(NetworkSpecifier other) {
// MatchAllNetworkSpecifier is taken care in NetworkCapabilities#satisfiedBySpecifier.
+ if (other instanceof WifiAwareAgentNetworkSpecifier) {
+ return ((WifiAwareAgentNetworkSpecifier) other).satisfiesAwareNetworkSpecifier(this);
+ }
return equals(other);
}
--- /dev/null
+/*
+ * 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 static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertEquals;
+
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ErrorCollector;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Unit test harness for WifiAwareAgentNetworkSpecifier class.
+ */
+@SmallTest
+public class WifiAwareAgentNetworkSpecifierTest {
+ @Rule
+ public ErrorCollector collector = new ErrorCollector();
+
+ @Test
+ public void testParcel() {
+ final int numNs = 10;
+
+ Set<WifiAwareNetworkSpecifier> nsSet = new HashSet<>();
+ for (int i = 0; i < numNs; ++i) {
+ nsSet.add(getDummyNetworkSpecifier(10 + i));
+ }
+ WifiAwareAgentNetworkSpecifier dut = new WifiAwareAgentNetworkSpecifier(
+ nsSet.toArray(new WifiAwareNetworkSpecifier[numNs]));
+
+ Parcel parcelW = Parcel.obtain();
+ dut.writeToParcel(parcelW, 0);
+ byte[] bytes = parcelW.marshall();
+ parcelW.recycle();
+
+ Parcel parcelR = Parcel.obtain();
+ parcelR.unmarshall(bytes, 0, bytes.length);
+ parcelR.setDataPosition(0);
+ WifiAwareAgentNetworkSpecifier rereadDut =
+ WifiAwareAgentNetworkSpecifier.CREATOR.createFromParcel(parcelR);
+
+ assertEquals(dut, rereadDut);
+ }
+
+ /**
+ * Validate that an empty agent network specifier doesn't match any base network specifier.
+ */
+ @Test
+ public void testEmptyDoesntMatchAnything() {
+ WifiAwareAgentNetworkSpecifier dut = new WifiAwareAgentNetworkSpecifier();
+ WifiAwareNetworkSpecifier ns = getDummyNetworkSpecifier(6);
+ collector.checkThat("No match expected", ns.satisfiedBy(dut), equalTo(false));
+ }
+
+ /**
+ * Validate that an agent network specifier constructed with a single entry matches that entry,
+ * and only that entry.
+ */
+ @Test
+ public void testSingleMatch() {
+ WifiAwareNetworkSpecifier nsThis = getDummyNetworkSpecifier(6);
+ WifiAwareAgentNetworkSpecifier dut = new WifiAwareAgentNetworkSpecifier(nsThis);
+ WifiAwareNetworkSpecifier nsOther = getDummyNetworkSpecifier(8);
+ collector.checkThat("Match expected", nsThis.satisfiedBy(dut), equalTo(true));
+ collector.checkThat("No match expected", nsOther.satisfiedBy(dut), equalTo(false));
+ }
+
+ /**
+ * Validate that an agent network specifier constructed with multiple entries matches all those
+ * entries - but none other.
+ */
+ @Test
+ public void testMultipleMatchesAllMembers() {
+ final int numNs = 10;
+
+ Set<WifiAwareNetworkSpecifier> nsSet = new HashSet<>();
+ for (int i = 0; i < numNs; ++i) {
+ nsSet.add(getDummyNetworkSpecifier(10 + i));
+ }
+
+ WifiAwareAgentNetworkSpecifier dut = new WifiAwareAgentNetworkSpecifier(
+ nsSet.toArray(new WifiAwareNetworkSpecifier[numNs]));
+ WifiAwareNetworkSpecifier nsOther = getDummyNetworkSpecifier(10000);
+
+ for (WifiAwareNetworkSpecifier nsThis: nsSet) {
+ collector.checkThat("Match expected", nsThis.satisfiedBy(dut), equalTo(true));
+ }
+ collector.checkThat("No match expected", nsOther.satisfiedBy(dut), equalTo(false));
+ }
+
+ /**
+ * Validate that agent network specifier matches against a super-set.
+ */
+ @Test
+ public void testMatchSuperset() {
+ final int numNs = 10;
+
+ Set<WifiAwareNetworkSpecifier> nsSet = new HashSet<>();
+ for (int i = 0; i < numNs; ++i) {
+ nsSet.add(getDummyNetworkSpecifier(10 + i));
+ }
+
+ WifiAwareAgentNetworkSpecifier oldNs = new WifiAwareAgentNetworkSpecifier(
+ nsSet.toArray(new WifiAwareNetworkSpecifier[nsSet.size()]));
+
+ nsSet.add(getDummyNetworkSpecifier(100 + numNs));
+ WifiAwareAgentNetworkSpecifier newNs = new WifiAwareAgentNetworkSpecifier(
+ nsSet.toArray(new WifiAwareNetworkSpecifier[nsSet.size()]));
+
+ collector.checkThat("Match expected", oldNs.satisfiedBy(newNs), equalTo(true));
+ }
+
+ /**
+ * Validate that agent network specifier does not match against a sub-set.
+ */
+ @Test
+ public void testNoMatchSubset() {
+ final int numNs = 10;
+
+ Set<WifiAwareNetworkSpecifier> nsSet = new HashSet<>();
+ for (int i = 0; i < numNs; ++i) {
+ nsSet.add(getDummyNetworkSpecifier(10 + i));
+ }
+
+ WifiAwareAgentNetworkSpecifier newNs = new WifiAwareAgentNetworkSpecifier(
+ nsSet.toArray(new WifiAwareNetworkSpecifier[nsSet.size()]));
+
+ nsSet.add(getDummyNetworkSpecifier(100 + numNs));
+ WifiAwareAgentNetworkSpecifier oldNs = new WifiAwareAgentNetworkSpecifier(
+ nsSet.toArray(new WifiAwareNetworkSpecifier[nsSet.size()]));
+
+ collector.checkThat("Match unexpected", oldNs.satisfiedBy(newNs), equalTo(false));
+ }
+
+ /**
+ * Validate that agent network specifier cannot be used as in network requests - i.e. that
+ * throws an exception when queried for UID validity.
+ */
+ @Test(expected = SecurityException.class)
+ public void testNoUsageInRequest() {
+ WifiAwareAgentNetworkSpecifier dut = new WifiAwareAgentNetworkSpecifier();
+
+ dut.assertValidFromUid(0);
+ }
+
+ // utilities
+
+ /**
+ * Returns a WifiAwareNetworkSpecifier with dummy (but valid) entries. Each can be
+ * differentiated (made unique) by specifying a different client ID.
+ */
+ WifiAwareNetworkSpecifier getDummyNetworkSpecifier(int clientId) {
+ return new WifiAwareNetworkSpecifier(WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_OOB,
+ WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, clientId, 0, 0, new byte[6],
+ null, null, 0);
+ }
+}