Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a5c1e920 authored by Android Build Merger (Role)'s avatar Android Build Merger (Role) Committed by Android (Google) Code Review
Browse files

Merge "Merge "[AWARE] Add a group network specifier allowing matches to...

Merge "Merge "[AWARE] Add a group network specifier allowing matches to multiple requests" into oc-mr1-dev am: 185a91c7 am: 21b3d10b"
parents d1309f01 7da25e8e
Loading
Loading
Loading
Loading
+226 −0
Original line number Diff line number Diff line
/*
 * 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));
        }
    }
}
+3 −0
Original line number Diff line number Diff line
@@ -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);
    }

+177 −0
Original line number Diff line number Diff line
/*
 * 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);
    }
}