Merge "[AWARE] Add a group network specifier allowing matches to multiple requests" into oc-mr1-dev

This commit is contained in:
TreeHugger Robot
2017-08-22 02:18:44 +00:00
committed by Android (Google) Code Review
3 changed files with 406 additions and 0 deletions

View File

@@ -0,0 +1,226 @@
/*
* 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));
}
}
}

View File

@@ -193,6 +193,9 @@ public final class WifiAwareNetworkSpecifier extends NetworkSpecifier implements
@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);
}

View File

@@ -0,0 +1,177 @@
/*
* 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);
}
}