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

Commit 1cd48dae authored by Pavel Maltsev's avatar Pavel Maltsev
Browse files

Extend network request to query networks w/o capabilites

Add another bit mask into NetworkCapabilities class that represents
unwanted capabilities and corresponding methods to add and remove them.

Bug: 72828388
Bug: 68762530

Test: runtest -x frameworks/base/tests/net/
Change-Id: Ie291167eb74fdb696c7ee145c8cc46ea8115d6ba
parent 7959e70e
Loading
Loading
Loading
Loading
+114 −28
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.net;

import android.annotation.IntDef;
import android.annotation.SystemApi;
import android.net.ConnectivityManager.NetworkCallback;
import android.os.Parcel;
import android.os.Parcelable;
@@ -68,6 +69,7 @@ public final class NetworkCapabilities implements Parcelable {
            mSignalStrength = nc.mSignalStrength;
            mUids = nc.mUids;
            mEstablishingVpnAppUid = nc.mEstablishingVpnAppUid;
            mUnwantedNetworkCapabilities = nc.mUnwantedNetworkCapabilities;
        }
    }

@@ -77,7 +79,7 @@ public final class NetworkCapabilities implements Parcelable {
     * @hide
     */
    public void clearAll() {
        mNetworkCapabilities = mTransportTypes = 0;
        mNetworkCapabilities = mTransportTypes = mUnwantedNetworkCapabilities = 0;
        mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
        mNetworkSpecifier = null;
        mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED;
@@ -91,6 +93,11 @@ public final class NetworkCapabilities implements Parcelable {
     */
    private long mNetworkCapabilities;

    /**
     * If any capabilities specified here they must not exist in the matching Network.
     */
    private long mUnwantedNetworkCapabilities;

    /** @hide */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(prefix = { "NET_CAPABILITY_" }, value = {
@@ -338,31 +345,55 @@ public final class NetworkCapabilities implements Parcelable {
     * Adds the given capability to this {@code NetworkCapability} instance.
     * Multiple capabilities may be applied sequentially.  Note that when searching
     * for a network to satisfy a request, all capabilities requested must be satisfied.
     * <p>
     * If the given capability was previously added to the list of unwanted capabilities
     * then the capability will also be removed from the list of unwanted capabilities.
     *
     * @param capability the capability to be added.
     * @return This NetworkCapabilities instance, to facilitate chaining.
     * @hide
     */
    public NetworkCapabilities addCapability(@NetCapability int capability) {
        if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) {
            throw new IllegalArgumentException("NetworkCapability out of range");
        }
        checkValidCapability(capability);
        mNetworkCapabilities |= 1 << capability;
        mUnwantedNetworkCapabilities &= ~(1 << capability);  // remove from unwanted capability list
        return this;
    }

    /**
     * Adds the given capability to the list of unwanted capabilities of this
     * {@code NetworkCapability} instance.  Multiple unwanted capabilities may be applied
     * sequentially.  Note that when searching for a network to satisfy a request, the network
     * must not contain any capability from unwanted capability list.
     * <p>
     * If the capability was previously added to the list of required capabilities (for
     * example, it was there by default or added using {@link #addCapability(int)} method), then
     * it will be removed from the list of required capabilities as well.
     *
     * @see #addCapability(int)
     * @hide
     */
    public void addUnwantedCapability(@NetCapability int capability) {
        checkValidCapability(capability);
        mUnwantedNetworkCapabilities |= 1 << capability;
        mNetworkCapabilities &= ~(1 << capability);  // remove from requested capabilities
    }

    /**
     * Removes (if found) the given capability from this {@code NetworkCapability} instance.
     * <p>
     * Note that this method removes capabilities that was added via {@link #addCapability(int)},
     * {@link #addUnwantedCapability(int)} or {@link #setCapabilities(int[], int[])} .
     *
     * @param capability the capability to be removed.
     * @return This NetworkCapabilities instance, to facilitate chaining.
     * @hide
     */
    public NetworkCapabilities removeCapability(@NetCapability int capability) {
        if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) {
            throw new IllegalArgumentException("NetworkCapability out of range");
        }
        mNetworkCapabilities &= ~(1 << capability);
        checkValidCapability(capability);
        final long mask = ~(1 << capability);
        mNetworkCapabilities &= mask;
        mUnwantedNetworkCapabilities &= mask;
        return this;
    }

@@ -391,31 +422,58 @@ public final class NetworkCapabilities implements Parcelable {
        return BitUtils.unpackBits(mNetworkCapabilities);
    }

    /**
     * Gets all the unwanted capabilities set on this {@code NetworkCapability} instance.
     *
     * @return an array of unwanted capability values for this instance.
     * @hide
     */
    public @NetCapability int[] getUnwantedCapabilities() {
        return BitUtils.unpackBits(mUnwantedNetworkCapabilities);
    }


    /**
     * Sets all the capabilities set on this {@code NetworkCapability} instance.
     * This overwrites any existing capabilities.
     *
     * @hide
     */
    public void setCapabilities(@NetCapability int[] capabilities) {
    public void setCapabilities(@NetCapability int[] capabilities,
            @NetCapability int[] unwantedCapabilities) {
        mNetworkCapabilities = BitUtils.packBits(capabilities);
        mUnwantedNetworkCapabilities = BitUtils.packBits(unwantedCapabilities);
    }

    /**
     * @deprecated use {@link #setCapabilities(int[], int[])}
     * @hide
     */
    @Deprecated
    public void setCapabilities(@NetCapability int[] capabilities) {
        setCapabilities(capabilities, new int[] {});
    }

    /**
     * Tests for the presence of a capabilitity on this instance.
     * Tests for the presence of a capability on this instance.
     *
     * @param capability the capabilities to be tested for.
     * @return {@code true} if set on this instance.
     */
    public boolean hasCapability(@NetCapability int capability) {
        if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) {
            return false;
        return isValidCapability(capability)
                && ((mNetworkCapabilities & (1 << capability)) != 0);
    }
        return ((mNetworkCapabilities & (1 << capability)) != 0);

    /** @hide */
    public boolean hasUnwantedCapability(@NetCapability int capability) {
        return isValidCapability(capability)
                && ((mUnwantedNetworkCapabilities & (1 << capability)) != 0);
    }

    private void combineNetCapabilities(NetworkCapabilities nc) {
        this.mNetworkCapabilities |= nc.mNetworkCapabilities;
        this.mUnwantedNetworkCapabilities |= nc.mUnwantedNetworkCapabilities;
    }

    /**
@@ -426,7 +484,9 @@ public final class NetworkCapabilities implements Parcelable {
     * @hide
     */
    public String describeFirstNonRequestableCapability() {
        final long nonRequestable = (mNetworkCapabilities & NON_REQUESTABLE_CAPABILITIES);
        final long nonRequestable = (mNetworkCapabilities | mUnwantedNetworkCapabilities)
                & NON_REQUESTABLE_CAPABILITIES;

        if (nonRequestable != 0) {
            return capabilityNameOf(BitUtils.unpackBits(nonRequestable)[0]);
        }
@@ -436,21 +496,29 @@ public final class NetworkCapabilities implements Parcelable {
    }

    private boolean satisfiedByNetCapabilities(NetworkCapabilities nc, boolean onlyImmutable) {
        long networkCapabilities = this.mNetworkCapabilities;
        long requestedCapabilities = mNetworkCapabilities;
        long requestedUnwantedCapabilities = mUnwantedNetworkCapabilities;
        long providedCapabilities = nc.mNetworkCapabilities;

        if (onlyImmutable) {
            networkCapabilities = networkCapabilities & ~MUTABLE_CAPABILITIES;
            requestedCapabilities &= ~MUTABLE_CAPABILITIES;
            requestedUnwantedCapabilities &= ~MUTABLE_CAPABILITIES;
        }
        return ((nc.mNetworkCapabilities & networkCapabilities) == networkCapabilities);
        return ((providedCapabilities & requestedCapabilities) == requestedCapabilities)
                && ((requestedUnwantedCapabilities & providedCapabilities) == 0);
    }

    /** @hide */
    public boolean equalsNetCapabilities(NetworkCapabilities nc) {
        return (nc.mNetworkCapabilities == this.mNetworkCapabilities);
        return (nc.mNetworkCapabilities == this.mNetworkCapabilities)
                && (nc.mUnwantedNetworkCapabilities == this.mUnwantedNetworkCapabilities);
    }

    private boolean equalsNetCapabilitiesRequestable(NetworkCapabilities that) {
        return ((this.mNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES) ==
                (that.mNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES));
                (that.mNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES))
                && ((this.mUnwantedNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES) ==
                (that.mUnwantedNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES));
    }

    /**
@@ -1178,15 +1246,17 @@ public final class NetworkCapabilities implements Parcelable {

    @Override
    public int hashCode() {
        return ((int) (mNetworkCapabilities & 0xFFFFFFFF)
        return (int) (mNetworkCapabilities & 0xFFFFFFFF)
                + ((int) (mNetworkCapabilities >> 32) * 3)
                + ((int) (mTransportTypes & 0xFFFFFFFF) * 5)
                + ((int) (mTransportTypes >> 32) * 7)
                + (mLinkUpBandwidthKbps * 11)
                + (mLinkDownBandwidthKbps * 13)
                + Objects.hashCode(mNetworkSpecifier) * 17
                + (mSignalStrength * 19)
                + Objects.hashCode(mUids) * 23);
                + ((int) (mUnwantedNetworkCapabilities & 0xFFFFFFFF) * 5)
                + ((int) (mUnwantedNetworkCapabilities >> 32) * 7)
                + ((int) (mTransportTypes & 0xFFFFFFFF) * 11)
                + ((int) (mTransportTypes >> 32) * 13)
                + (mLinkUpBandwidthKbps * 17)
                + (mLinkDownBandwidthKbps * 19)
                + Objects.hashCode(mNetworkSpecifier) * 23
                + (mSignalStrength * 29)
                + Objects.hashCode(mUids) * 31;
    }

    @Override
@@ -1196,6 +1266,7 @@ public final class NetworkCapabilities implements Parcelable {
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeLong(mNetworkCapabilities);
        dest.writeLong(mUnwantedNetworkCapabilities);
        dest.writeLong(mTransportTypes);
        dest.writeInt(mLinkUpBandwidthKbps);
        dest.writeInt(mLinkDownBandwidthKbps);
@@ -1211,6 +1282,7 @@ public final class NetworkCapabilities implements Parcelable {
                NetworkCapabilities netCap = new NetworkCapabilities();

                netCap.mNetworkCapabilities = in.readLong();
                netCap.mUnwantedNetworkCapabilities = in.readLong();
                netCap.mTransportTypes = in.readLong();
                netCap.mLinkUpBandwidthKbps = in.readInt();
                netCap.mLinkDownBandwidthKbps = in.readInt();
@@ -1239,6 +1311,11 @@ public final class NetworkCapabilities implements Parcelable {
            appendStringRepresentationOfBitMaskToStringBuilder(sb, mNetworkCapabilities,
                    NetworkCapabilities::capabilityNameOf, "&");
        }
        if (0 != mNetworkCapabilities) {
            sb.append(" Unwanted: ");
            appendStringRepresentationOfBitMaskToStringBuilder(sb, mUnwantedNetworkCapabilities,
                    NetworkCapabilities::capabilityNameOf, "&");
        }
        if (mLinkUpBandwidthKbps > 0) {
            sb.append(" LinkUpBandwidth>=").append(mLinkUpBandwidthKbps).append("Kbps");
        }
@@ -1364,4 +1441,13 @@ public final class NetworkCapabilities implements Parcelable {
        Preconditions.checkArgument(
                isValidTransport(transport), "Invalid TransportType " + transport);
    }

    private static boolean isValidCapability(@NetworkCapabilities.NetCapability int capability) {
        return capability >= MIN_NET_CAPABILITY && capability <= MAX_NET_CAPABILITY;
    }

    private static void checkValidCapability(@NetworkCapabilities.NetCapability int capability) {
        Preconditions.checkArgument(isValidCapability(capability),
                "NetworkCapability " + capability + "out of range");
    }
}
+23 −1
Original line number Diff line number Diff line
@@ -157,6 +157,9 @@ public class NetworkRequest implements Parcelable {
         * the requested network's required capabilities.  Note that when searching
         * for a network to satisfy a request, all capabilities requested must be
         * satisfied.
         * <p>
         * If the given capability was previously added to the list of unwanted capabilities
         * then the capability will also be removed from the list of unwanted capabilities.
         *
         * @param capability The capability to add.
         * @return The builder to facilitate chaining
@@ -168,7 +171,8 @@ public class NetworkRequest implements Parcelable {
        }

        /**
         * Removes (if found) the given capability from this builder instance.
         * Removes (if found) the given capability from this builder instance from both required
         * and unwanted capabilities lists.
         *
         * @param capability The capability to remove.
         * @return The builder to facilitate chaining.
@@ -192,6 +196,24 @@ public class NetworkRequest implements Parcelable {
            return this;
        }

        /**
         * Add a capability that must not exist in the requested network.
         * <p>
         * If the capability was previously added to the list of required capabilities (for
         * example, it was there by default or added using {@link #addCapability(int)} method), then
         * it will be removed from the list of required capabilities as well.
         *
         * @see #addCapability(int)
         *
         * @param capability The capability to add to unwanted capability list.
         * @return The builder to facilitate chaining.
         * @hide
         */
        public Builder addUnwantedCapability(@NetworkCapabilities.NetCapability int capability) {
            mNetworkCapabilities.addUnwantedCapability(capability);
            return this;
        }

        /**
         * Completely clears all the {@code NetworkCapabilities} from this builder instance,
         * removing even the capabilities that are set by default when the object is constructed.
+120 −0
Original line number Diff line number Diff line
@@ -17,19 +17,25 @@
package android.net;

import static android.net.NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
import static android.net.NetworkCapabilities.RESTRICTED_CAPABILITIES;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkCapabilities.UNRESTRICTED_CAPABILITIES;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
@@ -275,6 +281,120 @@ public class NetworkCapabilitiesTest {
        assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
    }

    @Test
    public void testUnwantedCapabilities() {
        NetworkCapabilities network = new NetworkCapabilities();

        NetworkCapabilities request = new NetworkCapabilities();
        assertTrue("Request: " + request + ", Network:" + network,
                request.satisfiedByNetworkCapabilities(network));

        // Adding capabilities that doesn't exist in the network anyway
        request.addUnwantedCapability(NET_CAPABILITY_WIFI_P2P);
        request.addUnwantedCapability(NET_CAPABILITY_NOT_METERED);
        assertTrue(request.satisfiedByNetworkCapabilities(network));
        assertArrayEquals(new int[] {NET_CAPABILITY_WIFI_P2P, NET_CAPABILITY_NOT_METERED},
                request.getUnwantedCapabilities());

        // This is a default capability, just want to make sure its there because we use it below.
        assertTrue(network.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));

        // Verify that adding unwanted capability will effectively remove it from capability list.
        request.addUnwantedCapability(NET_CAPABILITY_NOT_RESTRICTED);
        assertTrue(request.hasUnwantedCapability(NET_CAPABILITY_NOT_RESTRICTED));
        assertFalse(request.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));


        // Now this request won't be satisfied because network contains NOT_RESTRICTED.
        assertFalse(request.satisfiedByNetworkCapabilities(network));
        network.removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
        assertTrue(request.satisfiedByNetworkCapabilities(network));

        // Verify that adding capability will effectively remove it from unwanted list
        request.addCapability(NET_CAPABILITY_NOT_RESTRICTED);
        assertTrue(request.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
        assertFalse(request.hasUnwantedCapability(NET_CAPABILITY_NOT_RESTRICTED));

        assertFalse(request.satisfiedByNetworkCapabilities(network));
        network.addCapability(NET_CAPABILITY_NOT_RESTRICTED);
        assertTrue(request.satisfiedByNetworkCapabilities(network));
    }

    @Test
    public void testEqualsNetCapabilities() {
        int CAPABILITY = NET_CAPABILITY_MMS;  // An arbitrary not mutable capability.

        NetworkCapabilities nc1 = new NetworkCapabilities();
        NetworkCapabilities nc2 = new NetworkCapabilities();
        assertTrue(nc1.equalsNetCapabilities(nc2));
        assertEquals(nc1, nc2);

        nc1.addCapability(CAPABILITY);
        assertFalse(nc1.equalsNetCapabilities(nc2));
        assertNotEquals(nc1, nc2);
        nc2.addCapability(CAPABILITY);
        assertTrue(nc1.equalsNetCapabilities(nc2));
        assertEquals(nc1, nc2);

        nc1.addUnwantedCapability(CAPABILITY);
        assertFalse(nc1.equalsNetCapabilities(nc2));
        nc2.addUnwantedCapability(CAPABILITY);
        assertTrue(nc1.equalsNetCapabilities(nc2));

        nc1.removeCapability(CAPABILITY);
        assertFalse(nc1.equalsNetCapabilities(nc2));
        nc2.removeCapability(CAPABILITY);
        assertTrue(nc1.equalsNetCapabilities(nc2));
    }

    @Test
    public void testCombineCapabilities() {
        NetworkCapabilities nc1 = new NetworkCapabilities();
        NetworkCapabilities nc2 = new NetworkCapabilities();

        nc1.addUnwantedCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
        nc1.addCapability(NET_CAPABILITY_NOT_ROAMING);
        assertNotEquals(nc1, nc2);
        nc2.combineCapabilities(nc1);
        assertEquals(nc1, nc2);
        assertTrue(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING));
        assertTrue(nc2.hasUnwantedCapability(NET_CAPABILITY_CAPTIVE_PORTAL));

        // This will effectively move NOT_ROAMING capability from required to unwanted for nc1.
        nc1.addUnwantedCapability(NET_CAPABILITY_NOT_ROAMING);

        nc2.combineCapabilities(nc1);
        // We will get this capability in both requested and unwanted lists thus this request
        // will never be satisfied.
        assertTrue(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING));
        assertTrue(nc2.hasUnwantedCapability(NET_CAPABILITY_NOT_ROAMING));
    }

    @Test
    public void testSetCapabilities() {
        final int[] REQUIRED_CAPABILITIES = new int[] {
                NET_CAPABILITY_INTERNET, NET_CAPABILITY_NOT_VPN };
        final int[] UNWANTED_CAPABILITIES = new int[] {
                NET_CAPABILITY_NOT_RESTRICTED, NET_CAPABILITY_NOT_METERED
        };

        NetworkCapabilities nc1 = new NetworkCapabilities();
        NetworkCapabilities nc2 = new NetworkCapabilities();

        nc1.setCapabilities(REQUIRED_CAPABILITIES, UNWANTED_CAPABILITIES);
        assertArrayEquals(REQUIRED_CAPABILITIES, nc1.getCapabilities());

        // Verify that setting and adding capabilities leads to the same object state.
        nc2.clearAll();
        for (int cap : REQUIRED_CAPABILITIES) {
            nc2.addCapability(cap);
        }
        for (int cap : UNWANTED_CAPABILITIES) {
            nc2.addUnwantedCapability(cap);
        }
        assertEquals(nc1, nc2);
    }

    private void assertEqualsThroughMarshalling(NetworkCapabilities netCap) {
        Parcel p = Parcel.obtain();
        netCap.writeToParcel(p, /* flags */ 0);