[CS] Add a generic transport-specific information API
Add a generic transport-specific information container interface and
access methods. These can be used by a network factory to pass transport
(bearer)-specific network parameters to the app.
Bug: 117605977
Test: atest frameworks/base/tests/net/java/android/net (+new unit tests)
Change-Id: Ib7c83b677e1c02a2212265719813e648b0c9cc1b
diff --git a/api/current.txt b/api/current.txt
index 299700b..3836b8b 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -27531,6 +27531,7 @@
method public int describeContents();
method public int getLinkDownstreamBandwidthKbps();
method public int getLinkUpstreamBandwidthKbps();
+ method public android.net.TransportInfo getTransportInfo();
method public boolean hasCapability(int);
method public boolean hasTransport(int);
method public void writeToParcel(android.os.Parcel, int);
@@ -27739,6 +27740,9 @@
field public static final int UNSUPPORTED = -1; // 0xffffffff
}
+ public abstract interface TransportInfo {
+ }
+
public abstract class Uri implements java.lang.Comparable android.os.Parcelable {
method public abstract android.net.Uri.Builder buildUpon();
method public int compareTo(android.net.Uri);
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 0bdfca7..0c44a56 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -17,6 +17,7 @@
package android.net;
import android.annotation.IntDef;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
@@ -79,6 +80,7 @@
mNetworkCapabilities = mTransportTypes = mUnwantedNetworkCapabilities = 0;
mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
mNetworkSpecifier = null;
+ mTransportInfo = null;
mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED;
mUids = null;
mEstablishingVpnAppUid = INVALID_UID;
@@ -95,6 +97,7 @@
mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps;
mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps;
mNetworkSpecifier = nc.mNetworkSpecifier;
+ mTransportInfo = nc.mTransportInfo;
mSignalStrength = nc.mSignalStrength;
setUids(nc.mUids); // Will make the defensive copy
mEstablishingVpnAppUid = nc.mEstablishingVpnAppUid;
@@ -874,6 +877,7 @@
}
private NetworkSpecifier mNetworkSpecifier = null;
+ private TransportInfo mTransportInfo = null;
/**
* Sets the optional bearer specific network specifier.
@@ -899,6 +903,19 @@
}
/**
+ * Sets the optional transport specific information.
+ *
+ * @param transportInfo A concrete, parcelable framework class that extends
+ * {@link TransportInfo}.
+ * @return This NetworkCapabilities instance, to facilitate chaining.
+ * @hide
+ */
+ public NetworkCapabilities setTransportInfo(TransportInfo transportInfo) {
+ mTransportInfo = transportInfo;
+ return this;
+ }
+
+ /**
* Gets the optional bearer specific network specifier.
*
* @return The optional {@link NetworkSpecifier} specifying the bearer specific network
@@ -910,6 +927,19 @@
return mNetworkSpecifier;
}
+ /**
+ * Returns a transport-specific information container. The application may cast this
+ * container to a concrete sub-class based on its knowledge of the network request. The
+ * application should be able to deal with a {@code null} return value or an invalid case,
+ * e.g. use {@code instanceof} operation to verify expected type.
+ *
+ * @return A concrete implementation of the {@link TransportInfo} class or null if not
+ * available for the network.
+ */
+ @Nullable public TransportInfo getTransportInfo() {
+ return mTransportInfo;
+ }
+
private void combineSpecifiers(NetworkCapabilities nc) {
if (mNetworkSpecifier != null && !mNetworkSpecifier.equals(nc.mNetworkSpecifier)) {
throw new IllegalStateException("Can't combine two networkSpecifiers");
@@ -926,6 +956,17 @@
return Objects.equals(mNetworkSpecifier, nc.mNetworkSpecifier);
}
+ private void combineTransportInfos(NetworkCapabilities nc) {
+ if (mTransportInfo != null && !mTransportInfo.equals(nc.mTransportInfo)) {
+ throw new IllegalStateException("Can't combine two TransportInfos");
+ }
+ setTransportInfo(nc.mTransportInfo);
+ }
+
+ private boolean equalsTransportInfo(NetworkCapabilities nc) {
+ return Objects.equals(mTransportInfo, nc.mTransportInfo);
+ }
+
/**
* Magic value that indicates no signal strength provided. A request specifying this value is
* always satisfied.
@@ -1238,6 +1279,7 @@
combineTransportTypes(nc);
combineLinkBandwidths(nc);
combineSpecifiers(nc);
+ combineTransportInfos(nc);
combineSignalStrength(nc);
combineUids(nc);
combineSSIDs(nc);
@@ -1347,6 +1389,7 @@
&& equalsLinkBandwidths(that)
&& equalsSignalStrength(that)
&& equalsSpecifier(that)
+ && equalsTransportInfo(that)
&& equalsUids(that)
&& equalsSSID(that));
}
@@ -1364,7 +1407,8 @@
+ Objects.hashCode(mNetworkSpecifier) * 23
+ (mSignalStrength * 29)
+ Objects.hashCode(mUids) * 31
- + Objects.hashCode(mSSID) * 37;
+ + Objects.hashCode(mSSID) * 37
+ + Objects.hashCode(mTransportInfo) * 41;
}
@Override
@@ -1379,6 +1423,7 @@
dest.writeInt(mLinkUpBandwidthKbps);
dest.writeInt(mLinkDownBandwidthKbps);
dest.writeParcelable((Parcelable) mNetworkSpecifier, flags);
+ dest.writeParcelable((Parcelable) mTransportInfo, flags);
dest.writeInt(mSignalStrength);
dest.writeArraySet(mUids);
dest.writeString(mSSID);
@@ -1396,6 +1441,7 @@
netCap.mLinkUpBandwidthKbps = in.readInt();
netCap.mLinkDownBandwidthKbps = in.readInt();
netCap.mNetworkSpecifier = in.readParcelable(null);
+ netCap.mTransportInfo = in.readParcelable(null);
netCap.mSignalStrength = in.readInt();
netCap.mUids = (ArraySet<UidRange>) in.readArraySet(
null /* ClassLoader, null for default */);
@@ -1435,6 +1481,9 @@
if (mNetworkSpecifier != null) {
sb.append(" Specifier: <").append(mNetworkSpecifier).append(">");
}
+ if (mTransportInfo != null) {
+ sb.append(" TransportInfo: <").append(mTransportInfo).append(">");
+ }
if (hasSignalStrength()) {
sb.append(" SignalStrength: ").append(mSignalStrength);
}
@@ -1501,6 +1550,9 @@
if (mNetworkSpecifier != null) {
proto.write(NetworkCapabilitiesProto.NETWORK_SPECIFIER, mNetworkSpecifier.toString());
}
+ if (mTransportInfo != null) {
+ // TODO b/120653863: write transport-specific info to proto?
+ }
proto.write(NetworkCapabilitiesProto.CAN_REPORT_SIGNAL_STRENGTH, hasSignalStrength());
proto.write(NetworkCapabilitiesProto.SIGNAL_STRENGTH, mSignalStrength);
diff --git a/core/java/android/net/TransportInfo.java b/core/java/android/net/TransportInfo.java
new file mode 100644
index 0000000..b78d3fe
--- /dev/null
+++ b/core/java/android/net/TransportInfo.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2018 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;
+
+/**
+ * A container for transport-specific capabilities which is returned by
+ * {@link NetworkCapabilities#getTransportInfo()}. Specific networks
+ * may provide concrete implementations of this interface.
+ */
+public interface TransportInfo {
+}
diff --git a/tests/net/java/android/net/NetworkCapabilitiesTest.java b/tests/net/java/android/net/NetworkCapabilitiesTest.java
index b40921f..50aef1d 100644
--- a/tests/net/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/java/android/net/NetworkCapabilitiesTest.java
@@ -24,9 +24,9 @@
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_OEM_PAID;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
import static android.net.NetworkCapabilities.RESTRICTED_CAPABILITIES;
@@ -46,7 +46,6 @@
import android.test.suitebuilder.annotation.SmallTest;
import android.util.ArraySet;
-
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -457,6 +456,62 @@
assertEquals(nc1, nc2);
}
+ @Test
+ public void testSetNetworkSpecifierOnMultiTransportNc() {
+ // Sequence 1: Transport + Transport + NetworkSpecifier
+ NetworkCapabilities nc1 = new NetworkCapabilities();
+ nc1.addTransportType(TRANSPORT_CELLULAR).addTransportType(TRANSPORT_WIFI);
+ try {
+ nc1.setNetworkSpecifier(new StringNetworkSpecifier("specs"));
+ fail("Cannot set NetworkSpecifier on a NetworkCapability with multiple transports!");
+ } catch (IllegalStateException expected) {
+ // empty
+ }
+
+ // Sequence 2: Transport + NetworkSpecifier + Transport
+ NetworkCapabilities nc2 = new NetworkCapabilities();
+ nc2.addTransportType(TRANSPORT_CELLULAR).setNetworkSpecifier(
+ new StringNetworkSpecifier("specs"));
+ try {
+ nc2.addTransportType(TRANSPORT_WIFI);
+ fail("Cannot set NetworkSpecifier on a NetworkCapability with multiple transports!");
+ } catch (IllegalStateException expected) {
+ // empty
+ }
+ }
+
+ @Test
+ public void testSetTransportInfoOnMultiTransportNc() {
+ // Sequence 1: Transport + Transport + TransportInfo
+ NetworkCapabilities nc1 = new NetworkCapabilities();
+ nc1.addTransportType(TRANSPORT_CELLULAR).addTransportType(TRANSPORT_WIFI)
+ .setTransportInfo(new TransportInfo() {});
+
+ // Sequence 2: Transport + NetworkSpecifier + Transport
+ NetworkCapabilities nc2 = new NetworkCapabilities();
+ nc2.addTransportType(TRANSPORT_CELLULAR).setTransportInfo(new TransportInfo() {})
+ .addTransportType(TRANSPORT_WIFI);
+ }
+
+ @Test
+ public void testCombineTransportInfo() {
+ NetworkCapabilities nc1 = new NetworkCapabilities();
+ nc1.setTransportInfo(new TransportInfo() {
+ // empty
+ });
+ NetworkCapabilities nc2 = new NetworkCapabilities();
+ nc2.setTransportInfo(new TransportInfo() {
+ // empty
+ });
+
+ try {
+ nc1.combineCapabilities(nc2);
+ fail("Should not be able to combine NetworkCaabilities which contain TransportInfos");
+ } catch (IllegalStateException expected) {
+ // empty
+ }
+ }
+
private void assertEqualsThroughMarshalling(NetworkCapabilities netCap) {
Parcel p = Parcel.obtain();
netCap.writeToParcel(p, /* flags */ 0);