Merge "API review: access field by method" into rvc-dev
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 81735ac..2a323e5 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -145,16 +145,6 @@
public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
/**
- * A temporary hack until SUPL system can get off the legacy APIS.
- * They do too many network requests and the long list of apps listening
- * and waking due to the CONNECTIVITY_ACTION broadcast makes it expensive.
- * Use this broadcast intent instead for SUPL requests.
- * @hide
- */
- public static final String CONNECTIVITY_ACTION_SUPL =
- "android.net.conn.CONNECTIVITY_CHANGE_SUPL";
-
- /**
* The device has connected to a network that has presented a captive
* portal, which is blocking Internet connectivity. The user was presented
* with a notification that network sign in is required,
@@ -1517,84 +1507,6 @@
return null;
}
- /**
- * Guess what the network request was trying to say so that the resulting
- * network is accessible via the legacy (deprecated) API such as
- * requestRouteToHost.
- *
- * This means we should try to be fairly precise about transport and
- * capability but ignore things such as networkSpecifier.
- * If the request has more than one transport or capability it doesn't
- * match the old legacy requests (they selected only single transport/capability)
- * so this function cannot map the request to a single legacy type and
- * the resulting network will not be available to the legacy APIs.
- *
- * This code is only called from the requestNetwork API (L and above).
- *
- * Setting a legacy type causes CONNECTIVITY_ACTION broadcasts, which are expensive
- * because they wake up lots of apps - see http://b/23350688 . So we currently only
- * do this for SUPL requests, which are the only ones that we know need it. If
- * omitting these broadcasts causes unacceptable app breakage, then for backwards
- * compatibility we can send them:
- *
- * if (targetSdkVersion < Build.VERSION_CODES.M) && // legacy API unsupported >= M
- * targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP)) // requestNetwork not present < L
- *
- * TODO - This should be removed when the legacy APIs are removed.
- */
- private int inferLegacyTypeForNetworkCapabilities(NetworkCapabilities netCap) {
- if (netCap == null) {
- return TYPE_NONE;
- }
-
- if (!netCap.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
- return TYPE_NONE;
- }
-
- // Do this only for SUPL, until GnssLocationProvider is fixed. http://b/25876485 .
- if (!netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)) {
- // NOTE: if this causes app breakage, we should not just comment out this early return;
- // instead, we should make this early return conditional on the requesting app's target
- // SDK version, as described in the comment above.
- return TYPE_NONE;
- }
-
- String type = null;
- int result = TYPE_NONE;
-
- if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS)) {
- type = "enableCBS";
- result = TYPE_MOBILE_CBS;
- } else if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS)) {
- type = "enableIMS";
- result = TYPE_MOBILE_IMS;
- } else if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_FOTA)) {
- type = "enableFOTA";
- result = TYPE_MOBILE_FOTA;
- } else if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)) {
- type = "enableDUN";
- result = TYPE_MOBILE_DUN;
- } else if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)) {
- type = "enableSUPL";
- result = TYPE_MOBILE_SUPL;
- // back out this hack for mms as they no longer need this and it's causing
- // device slowdowns - b/23350688 (note, supl still needs this)
- //} else if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)) {
- // type = "enableMMS";
- // result = TYPE_MOBILE_MMS;
- } else if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
- type = "enableHIPRI";
- result = TYPE_MOBILE_HIPRI;
- }
- if (type != null) {
- NetworkCapabilities testCap = networkCapabilitiesForFeature(TYPE_MOBILE, type);
- if (testCap.equalsNetCapabilities(netCap) && testCap.equalsTransportTypes(netCap)) {
- return result;
- }
- }
- return TYPE_NONE;
- }
-
private int legacyTypeForNetworkCapabilities(NetworkCapabilities netCap) {
if (netCap == null) return TYPE_NONE;
if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS)) {
@@ -2575,13 +2487,13 @@
}
@Override
- public void onTetheringFailed(final int resultCode) {
+ public void onTetheringFailed(final int error) {
callback.onTetheringFailed();
}
};
final TetheringRequest request = new TetheringRequest.Builder(type)
- .setSilentProvisioning(!showProvisioningUi).build();
+ .setShouldShowEntitlementUi(showProvisioningUi).build();
mTetheringManager.startTethering(request, executor, tetheringCallback);
}
@@ -2801,11 +2713,12 @@
public static final int TETHER_ERROR_UNAVAIL_IFACE =
TetheringManager.TETHER_ERROR_UNAVAIL_IFACE;
/**
- * @deprecated Use {@link TetheringManager#TETHER_ERROR_MASTER_ERROR}.
+ * @deprecated Use {@link TetheringManager#TETHER_ERROR_INTERNAL_ERROR}.
* {@hide}
*/
@Deprecated
- public static final int TETHER_ERROR_MASTER_ERROR = TetheringManager.TETHER_ERROR_MASTER_ERROR;
+ public static final int TETHER_ERROR_MASTER_ERROR =
+ TetheringManager.TETHER_ERROR_INTERNAL_ERROR;
/**
* @deprecated Use {@link TetheringManager#TETHER_ERROR_TETHER_IFACE_ERROR}.
* {@hide}
@@ -2821,19 +2734,19 @@
public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR =
TetheringManager.TETHER_ERROR_UNTETHER_IFACE_ERROR;
/**
- * @deprecated Use {@link TetheringManager#TETHER_ERROR_ENABLE_NAT_ERROR}.
+ * @deprecated Use {@link TetheringManager#TETHER_ERROR_ENABLE_FORWARDING_ERROR}.
* {@hide}
*/
@Deprecated
public static final int TETHER_ERROR_ENABLE_NAT_ERROR =
- TetheringManager.TETHER_ERROR_ENABLE_NAT_ERROR;
+ TetheringManager.TETHER_ERROR_ENABLE_FORWARDING_ERROR;
/**
- * @deprecated Use {@link TetheringManager#TETHER_ERROR_DISABLE_NAT_ERROR}.
+ * @deprecated Use {@link TetheringManager#TETHER_ERROR_DISABLE_FORWARDING_ERROR}.
* {@hide}
*/
@Deprecated
public static final int TETHER_ERROR_DISABLE_NAT_ERROR =
- TetheringManager.TETHER_ERROR_DISABLE_NAT_ERROR;
+ TetheringManager.TETHER_ERROR_DISABLE_FORWARDING_ERROR;
/**
* @deprecated Use {@link TetheringManager#TETHER_ERROR_IFACE_CFG_ERROR}.
* {@hide}
@@ -2842,13 +2755,13 @@
public static final int TETHER_ERROR_IFACE_CFG_ERROR =
TetheringManager.TETHER_ERROR_IFACE_CFG_ERROR;
/**
- * @deprecated Use {@link TetheringManager#TETHER_ERROR_PROVISION_FAILED}.
+ * @deprecated Use {@link TetheringManager#TETHER_ERROR_PROVISIONING_FAILED}.
* {@hide}
*/
@SystemApi
@Deprecated
public static final int TETHER_ERROR_PROVISION_FAILED =
- TetheringManager.TETHER_ERROR_PROVISION_FAILED;
+ TetheringManager.TETHER_ERROR_PROVISIONING_FAILED;
/**
* @deprecated Use {@link TetheringManager#TETHER_ERROR_DHCPSERVER_ERROR}.
* {@hide}
@@ -2880,7 +2793,14 @@
@UnsupportedAppUsage
@Deprecated
public int getLastTetherError(String iface) {
- return mTetheringManager.getLastTetherError(iface);
+ int error = mTetheringManager.getLastTetherError(iface);
+ if (error == TetheringManager.TETHER_ERROR_UNKNOWN_TYPE) {
+ // TETHER_ERROR_UNKNOWN_TYPE was introduced with TetheringManager and has never been
+ // returned by ConnectivityManager. Convert it to the legacy TETHER_ERROR_UNKNOWN_IFACE
+ // instead.
+ error = TetheringManager.TETHER_ERROR_UNKNOWN_IFACE;
+ }
+ return error;
}
/** @hide */
@@ -3773,29 +3693,29 @@
/**
* Helper function to request a network with a particular legacy type.
*
- * @deprecated This is temporarily public for tethering to backwards compatibility that uses
- * the NetworkRequest API to request networks with legacy type and relies on
- * CONNECTIVITY_ACTION broadcasts instead of NetworkCallbacks. New caller should use
+ * This API is only for use in internal system code that requests networks with legacy type and
+ * relies on CONNECTIVITY_ACTION broadcasts instead of NetworkCallbacks. New caller should use
* {@link #requestNetwork(NetworkRequest, NetworkCallback, Handler)} instead.
*
- * TODO: update said system code to rely on NetworkCallbacks and make this method private.
-
* @param request {@link NetworkRequest} describing this request.
- * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
- * the callback must not be shared - it uniquely specifies this request.
* @param timeoutMs The time in milliseconds to attempt looking for a suitable network
* before {@link NetworkCallback#onUnavailable()} is called. The timeout must
* be a positive value (i.e. >0).
* @param legacyType to specify the network type(#TYPE_*).
* @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
+ * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
+ * the callback must not be shared - it uniquely specifies this request.
*
* @hide
*/
@SystemApi
- @Deprecated
+ @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK)
public void requestNetwork(@NonNull NetworkRequest request,
- @NonNull NetworkCallback networkCallback, int timeoutMs, int legacyType,
- @NonNull Handler handler) {
+ int timeoutMs, int legacyType, @NonNull Handler handler,
+ @NonNull NetworkCallback networkCallback) {
+ if (legacyType == TYPE_NONE) {
+ throw new IllegalArgumentException("TYPE_NONE is meaningless legacy type");
+ }
CallbackHandler cbHandler = new CallbackHandler(handler);
NetworkCapabilities nc = request.networkCapabilities;
sendRequestForNetwork(nc, networkCallback, timeoutMs, REQUEST, legacyType, cbHandler);
@@ -3893,9 +3813,9 @@
*/
public void requestNetwork(@NonNull NetworkRequest request,
@NonNull NetworkCallback networkCallback, @NonNull Handler handler) {
- int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities);
CallbackHandler cbHandler = new CallbackHandler(handler);
- requestNetwork(request, networkCallback, 0, legacyType, cbHandler);
+ NetworkCapabilities nc = request.networkCapabilities;
+ sendRequestForNetwork(nc, networkCallback, 0, REQUEST, TYPE_NONE, cbHandler);
}
/**
@@ -3928,8 +3848,9 @@
public void requestNetwork(@NonNull NetworkRequest request,
@NonNull NetworkCallback networkCallback, int timeoutMs) {
checkTimeout(timeoutMs);
- int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities);
- requestNetwork(request, networkCallback, timeoutMs, legacyType, getDefaultHandler());
+ NetworkCapabilities nc = request.networkCapabilities;
+ sendRequestForNetwork(nc, networkCallback, timeoutMs, REQUEST, TYPE_NONE,
+ getDefaultHandler());
}
/**
@@ -3954,9 +3875,9 @@
public void requestNetwork(@NonNull NetworkRequest request,
@NonNull NetworkCallback networkCallback, @NonNull Handler handler, int timeoutMs) {
checkTimeout(timeoutMs);
- int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities);
CallbackHandler cbHandler = new CallbackHandler(handler);
- requestNetwork(request, networkCallback, timeoutMs, legacyType, cbHandler);
+ NetworkCapabilities nc = request.networkCapabilities;
+ sendRequestForNetwork(nc, networkCallback, timeoutMs, REQUEST, TYPE_NONE, cbHandler);
}
/**
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 732ceb5..2c356e4 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -167,7 +167,19 @@
this(source, false /* parcelSensitiveFields */);
}
- private LinkProperties(@Nullable LinkProperties source, boolean parcelSensitiveFields) {
+ /**
+ * Create a copy of a {@link LinkProperties} that may preserve fields that were set
+ * based on the permissions of the process that originally received it.
+ *
+ * <p>By default {@link LinkProperties} does not preserve such fields during parceling, as
+ * they should not be shared outside of the process that receives them without appropriate
+ * checks.
+ * @param parcelSensitiveFields Whether the sensitive fields should be kept when parceling
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public LinkProperties(@Nullable LinkProperties source, boolean parcelSensitiveFields) {
mParcelSensitiveFields = parcelSensitiveFields;
if (source == null) return;
mIfaceName = source.mIfaceName;
@@ -674,17 +686,29 @@
route.getDestination(),
route.getGateway(),
mIfaceName,
- route.getType());
+ route.getType(),
+ route.getMtu());
+ }
+
+ private int findRouteIndexByDestination(RouteInfo route) {
+ for (int i = 0; i < mRoutes.size(); i++) {
+ if (mRoutes.get(i).isSameDestinationAs(route)) {
+ return i;
+ }
+ }
+ return -1;
}
/**
- * Adds a {@link RouteInfo} to this {@code LinkProperties}, if not present. If the
- * {@link RouteInfo} had an interface name set and that differs from the interface set for this
- * {@code LinkProperties} an {@link IllegalArgumentException} will be thrown. The proper
+ * Adds a {@link RouteInfo} to this {@code LinkProperties}, if a {@link RouteInfo}
+ * with the same destination exists with different properties (e.g., different MTU),
+ * it will be updated. If the {@link RouteInfo} had an interface name set and
+ * that differs from the interface set for this {@code LinkProperties} an
+ * {@link IllegalArgumentException} will be thrown. The proper
* course is to add either un-named or properly named {@link RouteInfo}.
*
* @param route A {@link RouteInfo} to add to this object.
- * @return {@code false} if the route was already present, {@code true} if it was added.
+ * @return {@code true} was added or updated, false otherwise.
*/
public boolean addRoute(@NonNull RouteInfo route) {
String routeIface = route.getInterface();
@@ -694,11 +718,20 @@
+ " vs. " + mIfaceName);
}
route = routeWithInterface(route);
- if (!mRoutes.contains(route)) {
+
+ int i = findRouteIndexByDestination(route);
+ if (i == -1) {
+ // Route was not present. Add it.
mRoutes.add(route);
return true;
+ } else if (mRoutes.get(i).equals(route)) {
+ // Route was present and has same properties. Do nothing.
+ return false;
+ } else {
+ // Route was present and has different properties. Update it.
+ mRoutes.set(i, route);
+ return true;
}
- return false;
}
/**
@@ -706,6 +739,7 @@
* specify an interface and the interface must match the interface of this
* {@code LinkProperties}, or it will not be removed.
*
+ * @param route A {@link RouteInfo} specifying the route to remove.
* @return {@code true} if the route was removed, {@code false} if it was not present.
*
* @hide
@@ -1561,22 +1595,6 @@
}
/**
- * Create a copy of this {@link LinkProperties} that will preserve fields that were set
- * based on the permissions of the process that received this {@link LinkProperties}.
- *
- * <p>By default {@link LinkProperties} does not preserve such fields during parceling, as
- * they should not be shared outside of the process that receives them without appropriate
- * checks.
- * @hide
- */
- @SystemApi
- @TestApi
- @NonNull
- public LinkProperties makeSensitiveFieldsParcelingCopy() {
- return new LinkProperties(this, true /* parcelSensitiveFields */);
- }
-
- /**
* Compares this {@code LinkProperties} instance against the target
* LinkProperties in {@code obj}. Two LinkPropertieses are equal if
* all their fields are equal in values.
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index 6f5471b..f807a49 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -64,7 +64,7 @@
* The unique id of the network.
* @hide
*/
- @SystemApi
+ @UnsupportedAppUsage
public final int netId;
// Objects used to perform per-network operations such as getSocketFactory
@@ -170,6 +170,17 @@
}
/**
+ * Get the unique id of the network.
+ *
+ * @hide
+ */
+ @TestApi
+ @SystemApi
+ public int getNetId() {
+ return netId;
+ }
+
+ /**
* Returns a netid marked with the Private DNS bypass flag.
*
* This flag must be kept in sync with the NETID_USE_LOCAL_NAMESERVERS flag
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 116e343..fcfcebd 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -19,6 +19,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
@@ -32,14 +33,13 @@
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.BitUtils;
import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
+import java.util.Arrays;
import java.util.Objects;
import java.util.Set;
import java.util.StringJoiner;
@@ -88,6 +88,7 @@
/**
* Completely clears the contents of this object, removing even the capabilities that are set
* by default when the object is constructed.
+ * @hide
*/
public void clearAll() {
mNetworkCapabilities = mTransportTypes = mUnwantedNetworkCapabilities = 0;
@@ -96,7 +97,7 @@
mTransportInfo = null;
mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED;
mUids = null;
- mAdministratorUids.clear();
+ mAdministratorUids = new int[0];
mOwnerUid = Process.INVALID_UID;
mSSID = null;
mPrivateDnsBroken = false;
@@ -415,11 +416,12 @@
/**
* 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.
+ * Note that when searching for a network to satisfy a request, all capabilities
+ * requested must be satisfied.
*
* @param capability the capability to be added.
* @return This NetworkCapabilities instance, to facilitate chaining.
+ * @hide
*/
public @NonNull NetworkCapabilities addCapability(@NetCapability int capability) {
// If the given capability was previously added to the list of unwanted capabilities
@@ -434,9 +436,9 @@
/**
* 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.
+ * {@code NetworkCapability} instance. 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
@@ -456,6 +458,7 @@
*
* @param capability the capability to be removed.
* @return This NetworkCapabilities instance, to facilitate chaining.
+ * @hide
*/
public @NonNull NetworkCapabilities removeCapability(@NetCapability int capability) {
// Note that this method removes capabilities that were added via addCapability(int),
@@ -470,7 +473,7 @@
/**
* Sets (or clears) the given capability on this {@link NetworkCapabilities}
* instance.
- *
+ * @hide
*/
public @NonNull NetworkCapabilities setCapability(@NetCapability int capability,
boolean value) {
@@ -730,7 +733,7 @@
/**
* Adds the given transport type to this {@code NetworkCapability} instance.
- * Multiple transports may be applied sequentially. Note that when searching
+ * Multiple transports may be applied. Note that when searching
* for a network to satisfy a request, any listed in the request will satisfy the request.
* For example {@code TRANSPORT_WIFI} and {@code TRANSPORT_ETHERNET} added to a
* {@code NetworkCapabilities} would cause either a Wi-Fi network or an Ethernet network
@@ -739,6 +742,7 @@
*
* @param transportType the transport type to be added.
* @return This NetworkCapabilities instance, to facilitate chaining.
+ * @hide
*/
public @NonNull NetworkCapabilities addTransportType(@Transport int transportType) {
checkValidTransportType(transportType);
@@ -851,6 +855,7 @@
/**
* Set the UID of the owner app.
+ * @hide
*/
public @NonNull NetworkCapabilities setOwnerUid(final int uid) {
mOwnerUid = uid;
@@ -868,6 +873,8 @@
* <li>The user's location toggle is on
* </ol>
*
+ * Instances of NetworkCapabilities sent to apps without the appropriate permissions will
+ * have this field cleared out.
*/
public int getOwnerUid() {
return mOwnerUid;
@@ -884,10 +891,10 @@
* empty unless the destination is 1) the System Server, or 2) Telephony. In either case, the
* receiving entity must have the ACCESS_FINE_LOCATION permission and target R+.
*/
- private final List<Integer> mAdministratorUids = new ArrayList<>();
+ private int[] mAdministratorUids = new int[0];
/**
- * Sets the list of UIDs that are administrators of this network.
+ * Sets the int[] of UIDs that are administrators of this network.
*
* <p>UIDs included in administratorUids gain administrator privileges over this Network.
* Examples of UIDs that should be included in administratorUids are:
@@ -906,24 +913,22 @@
* @hide
*/
@NonNull
- @SystemApi
- public NetworkCapabilities setAdministratorUids(
- @NonNull final List<Integer> administratorUids) {
- mAdministratorUids.clear();
- mAdministratorUids.addAll(administratorUids);
+ public NetworkCapabilities setAdministratorUids(@NonNull final int[] administratorUids) {
+ mAdministratorUids = Arrays.copyOf(administratorUids, administratorUids.length);
return this;
}
/**
- * Retrieves the list of UIDs that are administrators of this Network.
+ * Retrieves the UIDs that are administrators of this Network.
*
- * @return the List of UIDs that are administrators of this Network
+ * @return the int[] of UIDs that are administrators of this Network
* @hide
*/
@NonNull
@SystemApi
- public List<Integer> getAdministratorUids() {
- return Collections.unmodifiableList(mAdministratorUids);
+ @TestApi
+ public int[] getAdministratorUids() {
+ return Arrays.copyOf(mAdministratorUids, mAdministratorUids.length);
}
/**
@@ -944,15 +949,10 @@
* Sets the upstream bandwidth for this network in Kbps. This always only refers to
* the estimated first hop transport bandwidth.
* <p>
- * Note that when used to request a network, this specifies the minimum acceptable.
- * When received as the state of an existing network this specifies the typical
- * first hop bandwidth expected. This is never measured, but rather is inferred
- * from technology type and other link parameters. It could be used to differentiate
- * between very slow 1xRTT cellular links and other faster networks or even between
- * 802.11b vs 802.11AC wifi technologies. It should not be used to differentiate between
- * fast backhauls and slow backhauls.
+ * {@see Builder#setLinkUpstreamBandwidthKbps}
*
* @param upKbps the estimated first hop upstream (device to network) bandwidth.
+ * @hide
*/
public @NonNull NetworkCapabilities setLinkUpstreamBandwidthKbps(int upKbps) {
mLinkUpBandwidthKbps = upKbps;
@@ -973,15 +973,10 @@
* Sets the downstream bandwidth for this network in Kbps. This always only refers to
* the estimated first hop transport bandwidth.
* <p>
- * Note that when used to request a network, this specifies the minimum acceptable.
- * When received as the state of an existing network this specifies the typical
- * first hop bandwidth expected. This is never measured, but rather is inferred
- * from technology type and other link parameters. It could be used to differentiate
- * between very slow 1xRTT cellular links and other faster networks or even between
- * 802.11b vs 802.11AC wifi technologies. It should not be used to differentiate between
- * fast backhauls and slow backhauls.
+ * {@see Builder#setLinkUpstreamBandwidthKbps}
*
* @param downKbps the estimated first hop downstream (network to device) bandwidth.
+ * @hide
*/
public @NonNull NetworkCapabilities setLinkDownstreamBandwidthKbps(int downKbps) {
mLinkDownBandwidthKbps = downKbps;
@@ -1040,6 +1035,7 @@
* @param networkSpecifier A concrete, parcelable framework class that extends
* NetworkSpecifier.
* @return This NetworkCapabilities instance, to facilitate chaining.
+ * @hide
*/
public @NonNull NetworkCapabilities setNetworkSpecifier(
@NonNull NetworkSpecifier networkSpecifier) {
@@ -1061,7 +1057,6 @@
* @return This NetworkCapabilities instance, to facilitate chaining.
* @hide
*/
- @SystemApi
public @NonNull NetworkCapabilities setTransportInfo(@NonNull TransportInfo transportInfo) {
mTransportInfo = transportInfo;
return this;
@@ -1071,7 +1066,7 @@
* Gets the optional bearer specific network specifier. May be {@code null} if not set.
*
* @return The optional {@link NetworkSpecifier} specifying the bearer specific network
- * specifier or {@code null}. See {@link #setNetworkSpecifier}.
+ * specifier or {@code null}.
*/
public @Nullable NetworkSpecifier getNetworkSpecifier() {
return mNetworkSpecifier;
@@ -1141,6 +1136,7 @@
* effect when requesting a callback.
*
* @param signalStrength the bearer-specific signal strength.
+ * @hide
*/
public @NonNull NetworkCapabilities setSignalStrength(int signalStrength) {
mSignalStrength = signalStrength;
@@ -1367,7 +1363,6 @@
* Sets the SSID of this network.
* @hide
*/
- @SystemApi
public @NonNull NetworkCapabilities setSSID(@Nullable String ssid) {
mSSID = ssid;
return this;
@@ -1378,7 +1373,8 @@
* @hide
*/
@SystemApi
- public @Nullable String getSSID() {
+ @TestApi
+ public @Nullable String getSsid() {
return mSSID;
}
@@ -1584,7 +1580,7 @@
dest.writeArraySet(mUids);
dest.writeString(mSSID);
dest.writeBoolean(mPrivateDnsBroken);
- dest.writeList(mAdministratorUids);
+ dest.writeIntArray(mAdministratorUids);
dest.writeInt(mOwnerUid);
dest.writeInt(mRequestorUid);
dest.writeString(mRequestorPackageName);
@@ -1608,7 +1604,7 @@
null /* ClassLoader, null for default */);
netCap.mSSID = in.readString();
netCap.mPrivateDnsBroken = in.readBoolean();
- netCap.setAdministratorUids(in.readArrayList(null));
+ netCap.setAdministratorUids(in.createIntArray());
netCap.mOwnerUid = in.readInt();
netCap.mRequestorUid = in.readInt();
netCap.mRequestorPackageName = in.readString();
@@ -1665,8 +1661,8 @@
sb.append(" OwnerUid: ").append(mOwnerUid);
}
- if (!mAdministratorUids.isEmpty()) {
- sb.append(" AdministratorUids: ").append(mAdministratorUids);
+ if (mAdministratorUids.length == 0) {
+ sb.append(" AdministratorUids: ").append(Arrays.toString(mAdministratorUids));
}
if (null != mSSID) {
@@ -1858,25 +1854,32 @@
}
/**
- * Set the uid of the app making the request.
+ * Set the UID of the app making the request.
*
- * Note: This works only for {@link NetworkAgent} instances. Any capabilities passed in
- * via the public {@link ConnectivityManager} API's will have this field overwritten.
+ * For instances of NetworkCapabilities representing a request, sets the
+ * UID of the app making the request. For a network created by the system,
+ * sets the UID of the only app whose requests can match this network.
+ * This can be set to {@link Process#INVALID_UID} if there is no such app,
+ * or if this instance of NetworkCapabilities is about to be sent to a
+ * party that should not learn about this.
*
* @param uid UID of the app.
* @hide
*/
- @SystemApi
public @NonNull NetworkCapabilities setRequestorUid(int uid) {
mRequestorUid = uid;
return this;
}
/**
- * @return the uid of the app making the request.
+ * Returns the UID of the app making the request.
*
- * Note: This could return {@link Process#INVALID_UID} if the {@link NetworkRequest}
- * object was not obtained from {@link ConnectivityManager}.
+ * For a NetworkRequest being made by an app, contains the app's UID. For a network
+ * created by the system, contains the UID of the only app whose requests can match
+ * this network, or {@link Process#INVALID_UID} if none or if the
+ * caller does not have permission to learn about this.
+ *
+ * @return the uid of the app making the request.
* @hide
*/
public int getRequestorUid() {
@@ -1886,23 +1889,29 @@
/**
* Set the package name of the app making the request.
*
- * Note: This works only for {@link NetworkAgent} instances. Any capabilities passed in
- * via the public {@link ConnectivityManager} API's will have this field overwritten.
+ * For instances of NetworkCapabilities representing a request, sets the
+ * package name of the app making the request. For a network created by the system,
+ * sets the package name of the only app whose requests can match this network.
+ * This can be set to null if there is no such app, or if this instance of
+ * NetworkCapabilities is about to be sent to a party that should not learn about this.
*
* @param packageName package name of the app.
* @hide
*/
- @SystemApi
public @NonNull NetworkCapabilities setRequestorPackageName(@NonNull String packageName) {
mRequestorPackageName = packageName;
return this;
}
/**
- * @return the package name of the app making the request.
+ * Returns the package name of the app making the request.
*
- * Note: This could return {@code null} if the {@link NetworkRequest} object was not obtained
- * from {@link ConnectivityManager}.
+ * For a NetworkRequest being made by an app, contains the app's package name. For a
+ * network created by the system, contains the package name of the only app whose
+ * requests can match this network, or null if none or if the caller does not have
+ * permission to learn about this.
+ *
+ * @return the package name of the app making the request.
* @hide
*/
@Nullable
@@ -1911,9 +1920,9 @@
}
/**
- * Set the uid and package name of the app making the request.
+ * Set the uid and package name of the app causing this network to exist.
*
- * Note: This is intended to be only invoked from within connectivitiy service.
+ * {@see #setRequestorUid} and {@link #setRequestorPackageName}
*
* @param uid UID of the app.
* @param packageName package name of the app.
@@ -1972,4 +1981,316 @@
return mRequestorUid == nc.mRequestorUid
&& TextUtils.equals(mRequestorPackageName, nc.mRequestorPackageName);
}
+
+ /**
+ * Builder class for NetworkCapabilities.
+ *
+ * This class is mainly for for {@link NetworkAgent} instances to use. Many fields in
+ * the built class require holding a signature permission to use - mostly
+ * {@link android.Manifest.permission.NETWORK_FACTORY}, but refer to the specific
+ * description of each setter. As this class lives entirely in app space it does not
+ * enforce these restrictions itself but the system server clears out the relevant
+ * fields when receiving a NetworkCapabilities object from a caller without the
+ * appropriate permission.
+ *
+ * Apps don't use this builder directly. Instead, they use {@link NetworkRequest} via
+ * its builder object.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public static class Builder {
+ private final NetworkCapabilities mCaps;
+
+ /**
+ * Creates a new Builder to construct NetworkCapabilities objects.
+ */
+ public Builder() {
+ mCaps = new NetworkCapabilities();
+ }
+
+ /**
+ * Creates a new Builder of NetworkCapabilities from an existing instance.
+ */
+ public Builder(@NonNull final NetworkCapabilities nc) {
+ Objects.requireNonNull(nc);
+ mCaps = new NetworkCapabilities(nc);
+ }
+
+ /**
+ * Adds the given transport type.
+ *
+ * Multiple transports may be added. Note that when searching for a network to satisfy a
+ * request, satisfying any of the transports listed in the request will satisfy the request.
+ * For example {@code TRANSPORT_WIFI} and {@code TRANSPORT_ETHERNET} added to a
+ * {@code NetworkCapabilities} would cause either a Wi-Fi network or an Ethernet network
+ * to be selected. This is logically different than
+ * {@code NetworkCapabilities.NET_CAPABILITY_*}.
+ *
+ * @param transportType the transport type to be added or removed.
+ * @return this builder
+ */
+ @NonNull
+ public Builder addTransportType(@Transport int transportType) {
+ checkValidTransportType(transportType);
+ mCaps.addTransportType(transportType);
+ return this;
+ }
+
+ /**
+ * Removes the given transport type.
+ *
+ * {@see #addTransportType}.
+ *
+ * @param transportType the transport type to be added or removed.
+ * @return this builder
+ */
+ @NonNull
+ public Builder removeTransportType(@Transport int transportType) {
+ checkValidTransportType(transportType);
+ mCaps.removeTransportType(transportType);
+ return this;
+ }
+
+ /**
+ * Adds the given capability.
+ *
+ * @param capability the capability
+ * @return this builder
+ */
+ @NonNull
+ public Builder addCapability(@NetCapability final int capability) {
+ mCaps.setCapability(capability, true);
+ return this;
+ }
+
+ /**
+ * Removes the given capability.
+ *
+ * @param capability the capability
+ * @return this builder
+ */
+ @NonNull
+ public Builder removeCapability(@NetCapability final int capability) {
+ mCaps.setCapability(capability, false);
+ return this;
+ }
+
+ /**
+ * Sets the owner UID.
+ *
+ * The default value is {@link Process#INVALID_UID}. Pass this value to reset.
+ *
+ * Note: for security the system will clear out this field when received from a
+ * non-privileged source.
+ *
+ * @param ownerUid the owner UID
+ * @return this builder
+ */
+ @NonNull
+ @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+ public Builder setOwnerUid(final int ownerUid) {
+ mCaps.setOwnerUid(ownerUid);
+ return this;
+ }
+
+ /**
+ * Sets the list of UIDs that are administrators of this network.
+ *
+ * <p>UIDs included in administratorUids gain administrator privileges over this
+ * Network. Examples of UIDs that should be included in administratorUids are:
+ * <ul>
+ * <li>Carrier apps with privileges for the relevant subscription
+ * <li>Active VPN apps
+ * <li>Other application groups with a particular Network-related role
+ * </ul>
+ *
+ * <p>In general, user-supplied networks (such as WiFi networks) do not have
+ * administrators.
+ *
+ * <p>An app is granted owner privileges over Networks that it supplies. The owner
+ * UID MUST always be included in administratorUids.
+ *
+ * The default value is the empty array. Pass an empty array to reset.
+ *
+ * Note: for security the system will clear out this field when received from a
+ * non-privileged source, such as an app using reflection to call this or
+ * mutate the member in the built object.
+ *
+ * @param administratorUids the UIDs to be set as administrators of this Network.
+ * @return this builder
+ */
+ @NonNull
+ @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+ public Builder setAdministratorUids(@NonNull final int[] administratorUids) {
+ Objects.requireNonNull(administratorUids);
+ mCaps.setAdministratorUids(administratorUids);
+ return this;
+ }
+
+ /**
+ * Sets the upstream bandwidth of the link.
+ *
+ * Sets the upstream bandwidth for this network in Kbps. This always only refers to
+ * the estimated first hop transport bandwidth.
+ * <p>
+ * Note that when used to request a network, this specifies the minimum acceptable.
+ * When received as the state of an existing network this specifies the typical
+ * first hop bandwidth expected. This is never measured, but rather is inferred
+ * from technology type and other link parameters. It could be used to differentiate
+ * between very slow 1xRTT cellular links and other faster networks or even between
+ * 802.11b vs 802.11AC wifi technologies. It should not be used to differentiate between
+ * fast backhauls and slow backhauls.
+ *
+ * @param upKbps the estimated first hop upstream (device to network) bandwidth.
+ * @return this builder
+ */
+ @NonNull
+ public Builder setLinkUpstreamBandwidthKbps(final int upKbps) {
+ mCaps.setLinkUpstreamBandwidthKbps(upKbps);
+ return this;
+ }
+
+ /**
+ * Sets the downstream bandwidth for this network in Kbps. This always only refers to
+ * the estimated first hop transport bandwidth.
+ * <p>
+ * Note that when used to request a network, this specifies the minimum acceptable.
+ * When received as the state of an existing network this specifies the typical
+ * first hop bandwidth expected. This is never measured, but rather is inferred
+ * from technology type and other link parameters. It could be used to differentiate
+ * between very slow 1xRTT cellular links and other faster networks or even between
+ * 802.11b vs 802.11AC wifi technologies. It should not be used to differentiate between
+ * fast backhauls and slow backhauls.
+ *
+ * @param downKbps the estimated first hop downstream (network to device) bandwidth.
+ * @return this builder
+ */
+ @NonNull
+ public Builder setLinkDownstreamBandwidthKbps(final int downKbps) {
+ mCaps.setLinkDownstreamBandwidthKbps(downKbps);
+ return this;
+ }
+
+ /**
+ * Sets the optional bearer specific network specifier.
+ * This has no meaning if a single transport is also not specified, so calling
+ * this without a single transport set will generate an exception, as will
+ * subsequently adding or removing transports after this is set.
+ * </p>
+ *
+ * @param specifier a concrete, parcelable framework class that extends NetworkSpecifier,
+ * or null to clear it.
+ * @return this builder
+ */
+ @NonNull
+ public Builder setNetworkSpecifier(@Nullable final NetworkSpecifier specifier) {
+ mCaps.setNetworkSpecifier(specifier);
+ return this;
+ }
+
+ /**
+ * Sets the optional transport specific information.
+ *
+ * @param info A concrete, parcelable framework class that extends {@link TransportInfo},
+ * or null to clear it.
+ * @return this builder
+ */
+ @NonNull
+ public Builder setTransportInfo(@Nullable final TransportInfo info) {
+ mCaps.setTransportInfo(info);
+ return this;
+ }
+
+ /**
+ * Sets the signal strength. This is a signed integer, with higher values indicating a
+ * stronger signal. The exact units are bearer-dependent. For example, Wi-Fi uses the
+ * same RSSI units reported by wifi code.
+ * <p>
+ * Note that when used to register a network callback, this specifies the minimum
+ * acceptable signal strength. When received as the state of an existing network it
+ * specifies the current value. A value of code SIGNAL_STRENGTH_UNSPECIFIED} means
+ * no value when received and has no effect when requesting a callback.
+ *
+ * Note: for security the system will throw if it receives a NetworkRequest where
+ * the underlying NetworkCapabilities has this member set from a source that does
+ * not hold the {@link android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP}
+ * permission. Apps with this permission can use this indirectly through
+ * {@link android.net.NetworkRequest}.
+ *
+ * @param signalStrength the bearer-specific signal strength.
+ * @return this builder
+ */
+ @NonNull
+ @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP)
+ public Builder setSignalStrength(final int signalStrength) {
+ mCaps.setSignalStrength(signalStrength);
+ return this;
+ }
+
+ /**
+ * Sets the SSID of this network.
+ *
+ * Note: for security the system will clear out this field when received from a
+ * non-privileged source, like an app using reflection to set this.
+ *
+ * @param ssid the SSID, or null to clear it.
+ * @return this builder
+ */
+ @NonNull
+ @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+ public Builder setSsid(@Nullable final String ssid) {
+ mCaps.setSSID(ssid);
+ return this;
+ }
+
+ /**
+ * Set the uid of the app causing this network to exist.
+ *
+ * Note: for security the system will clear out this field when received from a
+ * non-privileged source.
+ *
+ * @param uid UID of the app.
+ * @return this builder
+ */
+ @NonNull
+ @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+ public Builder setRequestorUid(final int uid) {
+ mCaps.setRequestorUid(uid);
+ return this;
+ }
+
+ /**
+ * Set the package name of the app causing this network to exist.
+ *
+ * Note: for security the system will clear out this field when received from a
+ * non-privileged source.
+ *
+ * @param packageName package name of the app, or null to clear it.
+ * @return this builder
+ */
+ @NonNull
+ @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+ public Builder setRequestorPackageName(@Nullable final String packageName) {
+ mCaps.setRequestorPackageName(packageName);
+ return this;
+ }
+
+ /**
+ * Builds the instance of the capabilities.
+ *
+ * @return the built instance of NetworkCapabilities.
+ */
+ @NonNull
+ public NetworkCapabilities build() {
+ if (mCaps.getOwnerUid() != Process.INVALID_UID) {
+ if (!ArrayUtils.contains(mCaps.getAdministratorUids(), mCaps.getOwnerUid())) {
+ throw new IllegalStateException("The owner UID must be included in "
+ + " administrator UIDs.");
+ }
+ }
+ return new NetworkCapabilities(mCaps);
+ }
+ }
}
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index 2b9e9fe..fec2df4 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -527,6 +527,26 @@
}
/**
+ * Compares this RouteInfo object against the specified object and indicates if the
+ * destinations of both routes are equal.
+ * @return {@code true} if the route destinations are equal, {@code false} otherwise.
+ *
+ * @hide
+ */
+ public boolean isSameDestinationAs(@Nullable Object obj) {
+ if (this == obj) return true;
+
+ if (!(obj instanceof RouteInfo)) return false;
+
+ RouteInfo target = (RouteInfo) obj;
+
+ if (Objects.equals(mDestination, target.getDestination())) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
* Returns a hashcode for this <code>RouteInfo</code> object.
*/
public int hashCode() {
diff --git a/core/java/android/net/TestNetworkManager.java b/core/java/android/net/TestNetworkManager.java
index c3284df..a0a563b 100644
--- a/core/java/android/net/TestNetworkManager.java
+++ b/core/java/android/net/TestNetworkManager.java
@@ -30,6 +30,18 @@
*/
@TestApi
public class TestNetworkManager {
+ /**
+ * Prefix for tun interfaces created by this class.
+ * @hide
+ */
+ public static final String TEST_TUN_PREFIX = "testtun";
+
+ /**
+ * Prefix for tap interfaces created by this class.
+ * @hide
+ */
+ public static final String TEST_TAP_PREFIX = "testtap";
+
@NonNull private static final String TAG = TestNetworkManager.class.getSimpleName();
@NonNull private final ITestNetworkManager mService;
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index deae459..4d504e7 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -110,6 +110,7 @@
import android.net.PrivateDnsConfigParcel;
import android.net.ProxyInfo;
import android.net.RouteInfo;
+import android.net.RouteInfoParcel;
import android.net.SocketKeepalive;
import android.net.TetheringManager;
import android.net.UidRange;
@@ -120,6 +121,7 @@
import android.net.metrics.NetworkEvent;
import android.net.netlink.InetDiagMessage;
import android.net.shared.PrivateDnsConfig;
+import android.net.util.LinkPropertiesUtils.CompareOrUpdateResult;
import android.net.util.LinkPropertiesUtils.CompareResult;
import android.net.util.MultinetworkPolicyTracker;
import android.net.util.NetdService;
@@ -232,6 +234,7 @@
import java.util.StringJoiner;
import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Function;
/**
* @hide
@@ -1666,7 +1669,7 @@
if (newNc.getNetworkSpecifier() != null) {
newNc.setNetworkSpecifier(newNc.getNetworkSpecifier().redact());
}
- newNc.setAdministratorUids(Collections.EMPTY_LIST);
+ newNc.setAdministratorUids(new int[0]);
return newNc;
}
@@ -1710,7 +1713,7 @@
}
if (checkSettingsPermission(callerPid, callerUid)) {
- return lp.makeSensitiveFieldsParcelingCopy();
+ return new LinkProperties(lp, true /* parcelSensitiveFields */);
}
final LinkProperties newLp = new LinkProperties(lp);
@@ -1727,7 +1730,7 @@
nc.setSingleUid(callerUid);
}
nc.setRequestorUidAndPackageName(callerUid, callerPackageName);
- nc.setAdministratorUids(Collections.EMPTY_LIST);
+ nc.setAdministratorUids(new int[0]);
// Clear owner UID; this can never come from an app.
nc.setOwnerUid(INVALID_UID);
@@ -2237,14 +2240,9 @@
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
final NetworkInfo ni = intent.getParcelableExtra(
ConnectivityManager.EXTRA_NETWORK_INFO);
- if (ni.getType() == ConnectivityManager.TYPE_MOBILE_SUPL) {
- intent.setAction(ConnectivityManager.CONNECTIVITY_ACTION_SUPL);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- } else {
- BroadcastOptions opts = BroadcastOptions.makeBasic();
- opts.setMaxManifestReceiverApiLevel(Build.VERSION_CODES.M);
- options = opts.toBundle();
- }
+ final BroadcastOptions opts = BroadcastOptions.makeBasic();
+ opts.setMaxManifestReceiverApiLevel(Build.VERSION_CODES.M);
+ options = opts.toBundle();
final IBatteryStats bs = mDeps.getBatteryStatsService();
try {
bs.noteConnectivityChanged(intent.getIntExtra(
@@ -5333,7 +5331,7 @@
// specific SSID/SignalStrength, or the calling app has permission to do so.
private void ensureSufficientPermissionsForRequest(NetworkCapabilities nc,
int callerPid, int callerUid, String callerPackageName) {
- if (null != nc.getSSID() && !checkSettingsPermission(callerPid, callerUid)) {
+ if (null != nc.getSsid() && !checkSettingsPermission(callerPid, callerUid)) {
throw new SecurityException("Insufficient permissions to request a specific SSID");
}
@@ -5402,6 +5400,9 @@
public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities,
Messenger messenger, int timeoutMs, IBinder binder, int legacyType,
@NonNull String callingPackageName) {
+ if (legacyType != TYPE_NONE && !checkNetworkStackPermission()) {
+ throw new SecurityException("Insufficient permissions to specify legacy type");
+ }
final int callingUid = Binder.getCallingUid();
final NetworkRequest.Type type = (networkCapabilities == null)
? NetworkRequest.Type.TRACK_DEFAULT
@@ -5793,7 +5794,7 @@
nai.getAndSetNetworkCapabilities(mixInCapabilities(nai, nc));
final String extraInfo = networkInfo.getExtraInfo();
final String name = TextUtils.isEmpty(extraInfo)
- ? nai.networkCapabilities.getSSID() : extraInfo;
+ ? nai.networkCapabilities.getSsid() : extraInfo;
if (DBG) log("registerNetworkAgent " + nai);
final long token = Binder.clearCallingIdentity();
try {
@@ -5951,15 +5952,49 @@
}
}
+ // TODO: move to frameworks/libs/net.
+ private RouteInfoParcel convertRouteInfo(RouteInfo route) {
+ final String nextHop;
+
+ switch (route.getType()) {
+ case RouteInfo.RTN_UNICAST:
+ if (route.hasGateway()) {
+ nextHop = route.getGateway().getHostAddress();
+ } else {
+ nextHop = INetd.NEXTHOP_NONE;
+ }
+ break;
+ case RouteInfo.RTN_UNREACHABLE:
+ nextHop = INetd.NEXTHOP_UNREACHABLE;
+ break;
+ case RouteInfo.RTN_THROW:
+ nextHop = INetd.NEXTHOP_THROW;
+ break;
+ default:
+ nextHop = INetd.NEXTHOP_NONE;
+ break;
+ }
+
+ final RouteInfoParcel rip = new RouteInfoParcel();
+ rip.ifName = route.getInterface();
+ rip.destination = route.getDestination().toString();
+ rip.nextHop = nextHop;
+ rip.mtu = route.getMtu();
+
+ return rip;
+ }
+
/**
* Have netd update routes from oldLp to newLp.
* @return true if routes changed between oldLp and newLp
*/
private boolean updateRoutes(LinkProperties newLp, LinkProperties oldLp, int netId) {
- // Compare the route diff to determine which routes should be added and removed.
- CompareResult<RouteInfo> routeDiff = new CompareResult<>(
+ Function<RouteInfo, IpPrefix> getDestination = (r) -> r.getDestination();
+ // compare the route diff to determine which routes have been updated
+ CompareOrUpdateResult<IpPrefix, RouteInfo> routeDiff = new CompareOrUpdateResult<>(
oldLp != null ? oldLp.getAllRoutes() : null,
- newLp != null ? newLp.getAllRoutes() : null);
+ newLp != null ? newLp.getAllRoutes() : null,
+ getDestination);
// add routes before removing old in case it helps with continuous connectivity
@@ -5968,10 +6003,10 @@
if (route.hasGateway()) continue;
if (VDBG || DDBG) log("Adding Route [" + route + "] to network " + netId);
try {
- mNMS.addRoute(netId, route);
+ mNetd.networkAddRouteParcel(netId, convertRouteInfo(route));
} catch (Exception e) {
if ((route.getDestination().getAddress() instanceof Inet4Address) || VDBG) {
- loge("Exception in addRoute for non-gateway: " + e);
+ loge("Exception in networkAddRouteParcel for non-gateway: " + e);
}
}
}
@@ -5979,10 +6014,10 @@
if (!route.hasGateway()) continue;
if (VDBG || DDBG) log("Adding Route [" + route + "] to network " + netId);
try {
- mNMS.addRoute(netId, route);
+ mNetd.networkAddRouteParcel(netId, convertRouteInfo(route));
} catch (Exception e) {
if ((route.getGateway() instanceof Inet4Address) || VDBG) {
- loge("Exception in addRoute for gateway: " + e);
+ loge("Exception in networkAddRouteParcel for gateway: " + e);
}
}
}
@@ -5990,12 +6025,22 @@
for (RouteInfo route : routeDiff.removed) {
if (VDBG || DDBG) log("Removing Route [" + route + "] from network " + netId);
try {
- mNMS.removeRoute(netId, route);
+ mNetd.networkRemoveRouteParcel(netId, convertRouteInfo(route));
} catch (Exception e) {
- loge("Exception in removeRoute: " + e);
+ loge("Exception in networkRemoveRouteParcel: " + e);
}
}
- return !routeDiff.added.isEmpty() || !routeDiff.removed.isEmpty();
+
+ for (RouteInfo route : routeDiff.updated) {
+ if (VDBG || DDBG) log("Updating Route [" + route + "] from network " + netId);
+ try {
+ mNetd.networkUpdateRouteParcel(netId, convertRouteInfo(route));
+ } catch (Exception e) {
+ loge("Exception in networkUpdateRouteParcel: " + e);
+ }
+ }
+ return !routeDiff.added.isEmpty() || !routeDiff.removed.isEmpty()
+ || !routeDiff.updated.isEmpty();
}
private void updateDnses(LinkProperties newLp, LinkProperties oldLp, int netId) {
@@ -7864,7 +7909,7 @@
private void clearNetworkCapabilitiesUids(@NonNull NetworkCapabilities nc) {
nc.setUids(null);
- nc.setAdministratorUids(Collections.EMPTY_LIST);
+ nc.setAdministratorUids(new int[0]);
nc.setOwnerUid(Process.INVALID_UID);
}
@@ -7911,8 +7956,9 @@
}
// Administrator UIDs also contains the Owner UID
- if (nai.networkCapabilities.getAdministratorUids().contains(callbackUid)) {
- return true;
+ final int[] administratorUids = nai.networkCapabilities.getAdministratorUids();
+ for (final int uid : administratorUids) {
+ if (uid == callbackUid) return true;
}
return false;
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index f772a4a..0ea7346 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -16,6 +16,9 @@
package com.android.server;
+import static android.net.TestNetworkManager.TEST_TAP_PREFIX;
+import static android.net.TestNetworkManager.TEST_TUN_PREFIX;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -53,7 +56,6 @@
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
-import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
@@ -61,8 +63,6 @@
class TestNetworkService extends ITestNetworkManager.Stub {
@NonNull private static final String TAG = TestNetworkService.class.getSimpleName();
@NonNull private static final String TEST_NETWORK_TYPE = "TEST_NETWORK";
- @NonNull private static final String TEST_TUN_PREFIX = "testtun";
- @NonNull private static final String TEST_TAP_PREFIX = "testtap";
@NonNull private static final AtomicInteger sTestTunIndex = new AtomicInteger();
@NonNull private final Context mContext;
@@ -250,7 +250,7 @@
nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
nc.setNetworkSpecifier(new StringNetworkSpecifier(iface));
- nc.setAdministratorUids(intArrayToList(administratorUids));
+ nc.setAdministratorUids(administratorUids);
if (!isMetered) {
nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
}
@@ -293,14 +293,6 @@
return new TestNetworkAgent(looper, context, ni, nc, lp, callingUid, binder);
}
- private List<Integer> intArrayToList(@NonNull int[] array) {
- final List<Integer> list = new ArrayList<>(array.length);
- for (final int i : array) {
- list.add(i);
- }
- return list;
- }
-
/**
* Sets up a Network with extremely limited privileges, guarded by the MANAGE_TEST_NETWORKS
* permission.
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 0925de8..34b0aa2 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -150,7 +150,7 @@
if (nai != null) {
transportType = approximateTransportType(nai);
final String extraInfo = nai.networkInfo.getExtraInfo();
- name = TextUtils.isEmpty(extraInfo) ? nai.networkCapabilities.getSSID() : extraInfo;
+ name = TextUtils.isEmpty(extraInfo) ? nai.networkCapabilities.getSsid() : extraInfo;
// Only notify for Internet-capable networks.
if (!nai.networkCapabilities.hasCapability(NET_CAPABILITY_INTERNET)) return;
} else {
@@ -183,14 +183,14 @@
int icon = getIcon(transportType);
if (notifyType == NotificationType.NO_INTERNET && transportType == TRANSPORT_WIFI) {
title = r.getString(R.string.wifi_no_internet,
- WifiInfo.sanitizeSsid(nai.networkCapabilities.getSSID()));
+ WifiInfo.sanitizeSsid(nai.networkCapabilities.getSsid()));
details = r.getString(R.string.wifi_no_internet_detailed);
} else if (notifyType == NotificationType.PRIVATE_DNS_BROKEN) {
if (transportType == TRANSPORT_CELLULAR) {
title = r.getString(R.string.mobile_no_internet);
} else if (transportType == TRANSPORT_WIFI) {
title = r.getString(R.string.wifi_no_internet,
- WifiInfo.sanitizeSsid(nai.networkCapabilities.getSSID()));
+ WifiInfo.sanitizeSsid(nai.networkCapabilities.getSsid()));
} else {
title = r.getString(R.string.other_networks_no_internet);
}
@@ -198,19 +198,19 @@
} else if (notifyType == NotificationType.PARTIAL_CONNECTIVITY
&& transportType == TRANSPORT_WIFI) {
title = r.getString(R.string.network_partial_connectivity,
- WifiInfo.sanitizeSsid(nai.networkCapabilities.getSSID()));
+ WifiInfo.sanitizeSsid(nai.networkCapabilities.getSsid()));
details = r.getString(R.string.network_partial_connectivity_detailed);
} else if (notifyType == NotificationType.LOST_INTERNET &&
transportType == TRANSPORT_WIFI) {
title = r.getString(R.string.wifi_no_internet,
- WifiInfo.sanitizeSsid(nai.networkCapabilities.getSSID()));
+ WifiInfo.sanitizeSsid(nai.networkCapabilities.getSsid()));
details = r.getString(R.string.wifi_no_internet_detailed);
} else if (notifyType == NotificationType.SIGN_IN) {
switch (transportType) {
case TRANSPORT_WIFI:
title = r.getString(R.string.wifi_available_sign_in, 0);
details = r.getString(R.string.network_available_sign_in_detailed,
- WifiInfo.sanitizeSsid(nai.networkCapabilities.getSSID()));
+ WifiInfo.sanitizeSsid(nai.networkCapabilities.getSsid()));
break;
case TRANSPORT_CELLULAR:
title = r.getString(R.string.network_available_sign_in, 0);
diff --git a/tests/net/common/Android.bp b/tests/net/common/Android.bp
index e44d460..46d680f 100644
--- a/tests/net/common/Android.bp
+++ b/tests/net/common/Android.bp
@@ -20,6 +20,7 @@
name: "FrameworksNetCommonTests",
srcs: ["java/**/*.java", "java/**/*.kt"],
static_libs: [
+ "androidx.core_core",
"androidx.test.rules",
"junit",
"mockito-target-minus-junit4",
diff --git a/tests/net/common/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java
index 48b65e5..2b5720a 100644
--- a/tests/net/common/java/android/net/LinkPropertiesTest.java
+++ b/tests/net/common/java/android/net/LinkPropertiesTest.java
@@ -29,12 +29,19 @@
import android.net.LinkProperties.ProvisioningChange;
import android.net.util.LinkPropertiesUtils.CompareResult;
+import android.os.Build;
import android.system.OsConstants;
import android.util.ArraySet;
+import androidx.core.os.BuildCompat;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
+
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -50,6 +57,9 @@
@RunWith(AndroidJUnit4.class)
@SmallTest
public class LinkPropertiesTest {
+ @Rule
+ public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
+
private static final InetAddress ADDRV4 = address("75.208.6.1");
private static final InetAddress ADDRV6 = address("2001:0db8:85a3:0000:0000:8a2e:0370:7334");
private static final InetAddress DNS1 = address("75.208.7.1");
@@ -76,13 +86,23 @@
private static final LinkAddress LINKADDRV6 = new LinkAddress(ADDRV6, 128);
private static final LinkAddress LINKADDRV6LINKLOCAL = new LinkAddress("fe80::1/64");
private static final Uri CAPPORT_API_URL = Uri.parse("https://test.example.com/capportapi");
- private static final CaptivePortalData CAPPORT_DATA = new CaptivePortalData.Builder()
- .setVenueInfoUrl(Uri.parse("https://test.example.com/venue")).build();
+
+ // CaptivePortalData cannot be in a constant as it does not exist on Q.
+ // The test runner also crashes when scanning for tests if it is a return type.
+ private static Object getCaptivePortalData() {
+ return new CaptivePortalData.Builder()
+ .setVenueInfoUrl(Uri.parse("https://test.example.com/venue")).build();
+ }
private static InetAddress address(String addrString) {
return InetAddresses.parseNumericAddress(addrString);
}
+ private static boolean isAtLeastR() {
+ // BuildCompat.isAtLeastR is documented to return false on release SDKs (including R)
+ return Build.VERSION.SDK_INT > Build.VERSION_CODES.Q || BuildCompat.isAtLeastR();
+ }
+
private void checkEmpty(final LinkProperties lp) {
assertEquals(0, lp.getAllInterfaceNames().size());
assertEquals(0, lp.getAllAddresses().size());
@@ -98,14 +118,17 @@
assertNull(lp.getHttpProxy());
assertNull(lp.getTcpBufferSizes());
assertNull(lp.getNat64Prefix());
- assertNull(lp.getDhcpServerAddress());
assertFalse(lp.isProvisioned());
assertFalse(lp.isIpv4Provisioned());
assertFalse(lp.isIpv6Provisioned());
assertFalse(lp.isPrivateDnsActive());
- assertFalse(lp.isWakeOnLanSupported());
- assertNull(lp.getCaptivePortalApiUrl());
- assertNull(lp.getCaptivePortalData());
+
+ if (isAtLeastR()) {
+ assertNull(lp.getDhcpServerAddress());
+ assertFalse(lp.isWakeOnLanSupported());
+ assertNull(lp.getCaptivePortalApiUrl());
+ assertNull(lp.getCaptivePortalData());
+ }
}
private LinkProperties makeTestObject() {
@@ -127,10 +150,12 @@
lp.setMtu(MTU);
lp.setTcpBufferSizes(TCP_BUFFER_SIZES);
lp.setNat64Prefix(new IpPrefix("2001:db8:0:64::/96"));
- lp.setDhcpServerAddress(DHCPSERVER);
- lp.setWakeOnLanSupported(true);
- lp.setCaptivePortalApiUrl(CAPPORT_API_URL);
- lp.setCaptivePortalData(CAPPORT_DATA);
+ if (isAtLeastR()) {
+ lp.setDhcpServerAddress(DHCPSERVER);
+ lp.setWakeOnLanSupported(true);
+ lp.setCaptivePortalApiUrl(CAPPORT_API_URL);
+ lp.setCaptivePortalData((CaptivePortalData) getCaptivePortalData());
+ }
return lp;
}
@@ -169,14 +194,19 @@
assertTrue(source.isIdenticalTcpBufferSizes(target));
assertTrue(target.isIdenticalTcpBufferSizes(source));
- assertTrue(source.isIdenticalWakeOnLan(target));
- assertTrue(target.isIdenticalWakeOnLan(source));
+ if (isAtLeastR()) {
+ assertTrue(source.isIdenticalDhcpServerAddress(target));
+ assertTrue(source.isIdenticalDhcpServerAddress(source));
- assertTrue(source.isIdenticalCaptivePortalApiUrl(target));
- assertTrue(target.isIdenticalCaptivePortalApiUrl(source));
+ assertTrue(source.isIdenticalWakeOnLan(target));
+ assertTrue(target.isIdenticalWakeOnLan(source));
- assertTrue(source.isIdenticalCaptivePortalData(target));
- assertTrue(target.isIdenticalCaptivePortalData(source));
+ assertTrue(source.isIdenticalCaptivePortalApiUrl(target));
+ assertTrue(target.isIdenticalCaptivePortalApiUrl(source));
+
+ assertTrue(source.isIdenticalCaptivePortalData(target));
+ assertTrue(target.isIdenticalCaptivePortalData(source));
+ }
// Check result of equals().
assertTrue(source.equals(target));
@@ -943,8 +973,7 @@
assertEquals(new ArraySet<>(expectRemoved), (new ArraySet<>(result.removed)));
}
- @Test
- public void testLinkPropertiesParcelable() throws Exception {
+ private static LinkProperties makeLinkPropertiesForParceling() {
LinkProperties source = new LinkProperties();
source.setInterfaceName(NAME);
@@ -978,17 +1007,29 @@
source.setNat64Prefix(new IpPrefix("2001:db8:1:2:64:64::/96"));
- source.setWakeOnLanSupported(true);
- source.setCaptivePortalApiUrl(CAPPORT_API_URL);
- source.setCaptivePortalData(CAPPORT_DATA);
-
- source.setDhcpServerAddress((Inet4Address) GATEWAY1);
-
final LinkProperties stacked = new LinkProperties();
stacked.setInterfaceName("test-stacked");
source.addStackedLink(stacked);
- assertParcelSane(source.makeSensitiveFieldsParcelingCopy(), 18 /* fieldCount */);
+ return source;
+ }
+
+ @Test @IgnoreAfter(Build.VERSION_CODES.Q)
+ public void testLinkPropertiesParcelable_Q() throws Exception {
+ final LinkProperties source = makeLinkPropertiesForParceling();
+ assertParcelSane(source, 14 /* fieldCount */);
+ }
+
+ @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
+ public void testLinkPropertiesParcelable() throws Exception {
+ final LinkProperties source = makeLinkPropertiesForParceling();
+
+ source.setWakeOnLanSupported(true);
+ source.setCaptivePortalApiUrl(CAPPORT_API_URL);
+ source.setCaptivePortalData((CaptivePortalData) getCaptivePortalData());
+ source.setDhcpServerAddress((Inet4Address) GATEWAY1);
+ assertParcelSane(new LinkProperties(source, true /* parcelSensitiveFields */),
+ 18 /* fieldCount */);
// Verify that without using a sensitiveFieldsParcelingCopy, sensitive fields are cleared.
final LinkProperties sanitized = new LinkProperties(source);
@@ -997,7 +1038,8 @@
assertEquals(sanitized, parcelingRoundTrip(source));
}
- @Test
+ // Parceling of the scope was broken until Q-QPR2
+ @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
public void testLinkLocalDnsServerParceling() throws Exception {
final String strAddress = "fe80::1%lo";
final LinkProperties lp = new LinkProperties();
@@ -1120,7 +1162,7 @@
assertFalse(lp.isPrivateDnsActive());
}
- @Test
+ @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
public void testDhcpServerAddress() {
final LinkProperties lp = makeTestObject();
assertEquals(DHCPSERVER, lp.getDhcpServerAddress());
@@ -1129,7 +1171,7 @@
assertNull(lp.getDhcpServerAddress());
}
- @Test
+ @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
public void testWakeOnLanSupported() {
final LinkProperties lp = makeTestObject();
assertTrue(lp.isWakeOnLanSupported());
@@ -1138,7 +1180,7 @@
assertFalse(lp.isWakeOnLanSupported());
}
- @Test
+ @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
public void testCaptivePortalApiUrl() {
final LinkProperties lp = makeTestObject();
assertEquals(CAPPORT_API_URL, lp.getCaptivePortalApiUrl());
@@ -1147,10 +1189,10 @@
assertNull(lp.getCaptivePortalApiUrl());
}
- @Test
+ @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
public void testCaptivePortalData() {
final LinkProperties lp = makeTestObject();
- assertEquals(CAPPORT_DATA, lp.getCaptivePortalData());
+ assertEquals(getCaptivePortalData(), lp.getCaptivePortalData());
lp.clear();
assertNull(lp.getCaptivePortalData());
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index efea91a..b2e8c37 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -48,9 +48,11 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.os.Build;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.ArraySet;
+import androidx.core.os.BuildCompat;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
@@ -64,6 +66,13 @@
private static final String TEST_SSID = "TEST_SSID";
private static final String DIFFERENT_TEST_SSID = "DIFFERENT_TEST_SSID";
+ private boolean isAtLeastR() {
+ // BuildCompat.isAtLeastR() is used to check the Android version before releasing Android R.
+ // Build.VERSION.SDK_INT > Build.VERSION_CODES.Q is used to check the Android version after
+ // releasing Android R.
+ return BuildCompat.isAtLeastR() || Build.VERSION.SDK_INT > Build.VERSION_CODES.Q;
+ }
+
@Test
public void testMaybeMarkCapabilitiesRestricted() {
// verify EIMS is restricted
@@ -269,25 +278,36 @@
.setUids(uids)
.addCapability(NET_CAPABILITY_EIMS)
.addCapability(NET_CAPABILITY_NOT_METERED);
- netCap.setOwnerUid(123);
+ if (isAtLeastR()) {
+ netCap.setOwnerUid(123);
+ }
assertParcelingIsLossless(netCap);
netCap.setSSID(TEST_SSID);
- assertParcelSane(netCap, 15);
+ testParcelSane(netCap);
}
@Test
public void testParcelNetworkCapabilitiesWithRequestorUidAndPackageName() {
final NetworkCapabilities netCap = new NetworkCapabilities()
.addCapability(NET_CAPABILITY_INTERNET)
- .setRequestorUid(9304)
- .setRequestorPackageName("com.android.test")
.addCapability(NET_CAPABILITY_EIMS)
.addCapability(NET_CAPABILITY_NOT_METERED);
+ if (isAtLeastR()) {
+ netCap.setRequestorPackageName("com.android.test");
+ netCap.setRequestorUid(9304);
+ }
assertParcelingIsLossless(netCap);
netCap.setSSID(TEST_SSID);
- assertParcelSane(netCap, 15);
+ testParcelSane(netCap);
}
+ private void testParcelSane(NetworkCapabilities cap) {
+ if (isAtLeastR()) {
+ assertParcelSane(cap, 15);
+ } else {
+ assertParcelSane(cap, 11);
+ }
+ }
@Test
public void testOemPaid() {
@@ -443,7 +463,7 @@
nc1.setSSID(TEST_SSID);
nc2.combineCapabilities(nc1);
- assertTrue(TEST_SSID.equals(nc2.getSSID()));
+ assertTrue(TEST_SSID.equals(nc2.getSsid()));
// Because they now have the same SSID, the following call should not throw
nc2.combineCapabilities(nc1);
@@ -581,12 +601,12 @@
// from nc2.
assertFalse(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING));
assertTrue(nc2.hasUnwantedCapability(NET_CAPABILITY_NOT_ROAMING));
- assertTrue(TEST_SSID.equals(nc2.getSSID()));
+ assertTrue(TEST_SSID.equals(nc2.getSsid()));
nc1.setSSID(DIFFERENT_TEST_SSID);
nc2.set(nc1);
assertEquals(nc1, nc2);
- assertTrue(DIFFERENT_TEST_SSID.equals(nc2.getSSID()));
+ assertTrue(DIFFERENT_TEST_SSID.equals(nc2.getSsid()));
nc1.setUids(uidRange(10, 13));
nc2.set(nc1); // Overwrites, as opposed to combineCapabilities
diff --git a/tests/net/java/android/net/NetworkTemplateTest.kt b/tests/net/java/android/net/NetworkTemplateTest.kt
new file mode 100644
index 0000000..5dd0fda
--- /dev/null
+++ b/tests/net/java/android/net/NetworkTemplateTest.kt
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2020 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
+
+import android.content.Context
+import android.net.ConnectivityManager.TYPE_MOBILE
+import android.net.ConnectivityManager.TYPE_WIFI
+import android.net.NetworkIdentity.SUBTYPE_COMBINED
+import android.net.NetworkIdentity.buildNetworkIdentity
+import android.net.NetworkStats.DEFAULT_NETWORK_ALL
+import android.net.NetworkStats.METERED_ALL
+import android.net.NetworkStats.ROAMING_ALL
+import android.net.NetworkTemplate.MATCH_MOBILE
+import android.net.NetworkTemplate.MATCH_WIFI
+import android.net.NetworkTemplate.NETWORK_TYPE_ALL
+import android.net.NetworkTemplate.buildTemplateMobileWithRatType
+import android.telephony.TelephonyManager
+import com.android.testutils.assertParcelSane
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.mock
+import org.mockito.MockitoAnnotations
+import kotlin.test.assertFalse
+import kotlin.test.assertNotEquals
+import kotlin.test.assertTrue
+
+private const val TEST_IMSI1 = "imsi1"
+private const val TEST_IMSI2 = "imsi2"
+private const val TEST_SSID1 = "ssid1"
+
+@RunWith(JUnit4::class)
+class NetworkTemplateTest {
+ private val mockContext = mock(Context::class.java)
+
+ private fun buildMobileNetworkState(subscriberId: String): NetworkState =
+ buildNetworkState(TYPE_MOBILE, subscriberId = subscriberId)
+ private fun buildWifiNetworkState(ssid: String): NetworkState =
+ buildNetworkState(TYPE_WIFI, ssid = ssid)
+
+ private fun buildNetworkState(
+ type: Int,
+ subscriberId: String? = null,
+ ssid: String? = null
+ ): NetworkState {
+ val info = mock(NetworkInfo::class.java)
+ doReturn(type).`when`(info).type
+ doReturn(NetworkInfo.State.CONNECTED).`when`(info).state
+ val lp = LinkProperties()
+ val caps = NetworkCapabilities().apply {
+ setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false)
+ setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true)
+ }
+ return NetworkState(info, lp, caps, mock(Network::class.java), subscriberId, ssid)
+ }
+
+ private fun NetworkTemplate.assertMatches(ident: NetworkIdentity) =
+ assertTrue(matches(ident), "$this does not match $ident")
+
+ private fun NetworkTemplate.assertDoesNotMatch(ident: NetworkIdentity) =
+ assertFalse(matches(ident), "$this should match $ident")
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ }
+
+ @Test
+ fun testRatTypeGroupMatches() {
+ val stateMobile = buildMobileNetworkState(TEST_IMSI1)
+ // Build UMTS template that matches mobile identities with RAT in the same
+ // group with any IMSI. See {@link NetworkTemplate#getCollapsedRatType}.
+ val templateUmts = buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UMTS)
+ // Build normal template that matches mobile identities with any RAT and IMSI.
+ val templateAll = buildTemplateMobileWithRatType(null, NETWORK_TYPE_ALL)
+ // Build template with UNKNOWN RAT that matches mobile identities with RAT that
+ // cannot be determined.
+ val templateUnknown =
+ buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UNKNOWN)
+
+ val identUmts = buildNetworkIdentity(
+ mockContext, stateMobile, false, TelephonyManager.NETWORK_TYPE_UMTS)
+ val identHsdpa = buildNetworkIdentity(
+ mockContext, stateMobile, false, TelephonyManager.NETWORK_TYPE_HSDPA)
+ val identLte = buildNetworkIdentity(
+ mockContext, stateMobile, false, TelephonyManager.NETWORK_TYPE_LTE)
+ val identCombined = buildNetworkIdentity(
+ mockContext, stateMobile, false, SUBTYPE_COMBINED)
+ val identImsi2 = buildNetworkIdentity(mockContext, buildMobileNetworkState(TEST_IMSI2),
+ false, TelephonyManager.NETWORK_TYPE_UMTS)
+ val identWifi = buildNetworkIdentity(
+ mockContext, buildWifiNetworkState(TEST_SSID1), true, 0)
+
+ // Assert that identity with the same RAT matches.
+ templateUmts.assertMatches(identUmts)
+ templateAll.assertMatches(identUmts)
+ templateUnknown.assertDoesNotMatch(identUmts)
+ // Assert that identity with the RAT within the same group matches.
+ templateUmts.assertMatches(identHsdpa)
+ templateAll.assertMatches(identHsdpa)
+ templateUnknown.assertDoesNotMatch(identHsdpa)
+ // Assert that identity with the RAT out of the same group only matches template with
+ // NETWORK_TYPE_ALL.
+ templateUmts.assertDoesNotMatch(identLte)
+ templateAll.assertMatches(identLte)
+ templateUnknown.assertDoesNotMatch(identLte)
+ // Assert that identity with combined RAT only matches with template with NETWORK_TYPE_ALL
+ // and NETWORK_TYPE_UNKNOWN.
+ templateUmts.assertDoesNotMatch(identCombined)
+ templateAll.assertMatches(identCombined)
+ templateUnknown.assertMatches(identCombined)
+ // Assert that identity with different IMSI matches.
+ templateUmts.assertMatches(identImsi2)
+ templateAll.assertMatches(identImsi2)
+ templateUnknown.assertDoesNotMatch(identImsi2)
+ // Assert that wifi identity does not match.
+ templateUmts.assertDoesNotMatch(identWifi)
+ templateAll.assertDoesNotMatch(identWifi)
+ templateUnknown.assertDoesNotMatch(identWifi)
+ }
+
+ @Test
+ fun testParcelUnparcel() {
+ val templateMobile = NetworkTemplate(MATCH_MOBILE, TEST_IMSI1, null, null, METERED_ALL,
+ ROAMING_ALL, DEFAULT_NETWORK_ALL, TelephonyManager.NETWORK_TYPE_LTE)
+ val templateWifi = NetworkTemplate(MATCH_WIFI, null, null, TEST_SSID1, METERED_ALL,
+ ROAMING_ALL, DEFAULT_NETWORK_ALL, 0)
+ assertParcelSane(templateMobile, 8)
+ assertParcelSane(templateWifi, 8)
+ }
+
+ // Verify NETWORK_TYPE_ALL does not conflict with TelephonyManager#NETWORK_TYPE_* constants.
+ @Test
+ fun testNetworkTypeAll() {
+ for (ratType in TelephonyManager.getAllNetworkTypes()) {
+ assertNotEquals(NETWORK_TYPE_ALL, ratType)
+ }
+ }
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index c21772a..4bfb51b 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -25,7 +25,6 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
-import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_SUPL;
import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO;
import static android.net.ConnectivityManager.EXTRA_NETWORK_TYPE;
import static android.net.ConnectivityManager.NETID_UNSET;
@@ -175,6 +174,7 @@
import android.net.ProxyInfo;
import android.net.ResolverParamsParcel;
import android.net.RouteInfo;
+import android.net.RouteInfoParcel;
import android.net.SocketKeepalive;
import android.net.UidRange;
import android.net.Uri;
@@ -427,7 +427,6 @@
public Object getSystemService(String name) {
if (Context.CONNECTIVITY_SERVICE.equals(name)) return mCm;
if (Context.NOTIFICATION_SERVICE.equals(name)) return mNotificationManager;
- if (Context.NETWORK_STACK_SERVICE.equals(name)) return mNetworkStack;
if (Context.USER_SERVICE.equals(name)) return mUserManager;
if (Context.ALARM_SERVICE.equals(name)) return mAlarmManager;
if (Context.LOCATION_SERVICE.equals(name)) return mLocationManager;
@@ -1374,7 +1373,6 @@
@NonNull final Predicate<Intent> filter) {
final ConditionVariable cv = new ConditionVariable();
final IntentFilter intentFilter = new IntentFilter(CONNECTIVITY_ACTION);
- intentFilter.addAction(CONNECTIVITY_ACTION_SUPL);
final BroadcastReceiver receiver = new BroadcastReceiver() {
private int remaining = count;
public void onReceive(Context context, Intent intent) {
@@ -1422,56 +1420,28 @@
final NetworkRequest legacyRequest = new NetworkRequest(legacyCaps, TYPE_MOBILE_SUPL,
ConnectivityManager.REQUEST_ID_UNSET, NetworkRequest.Type.REQUEST);
- // Send request and check that the legacy broadcast for SUPL is sent correctly.
+ // File request, withdraw it and make sure no broadcast is sent
+ final ConditionVariable cv2 = registerConnectivityBroadcast(1);
final TestNetworkCallback callback = new TestNetworkCallback();
- final ConditionVariable cv2 = registerConnectivityBroadcastThat(1,
- intent -> intent.getIntExtra(EXTRA_NETWORK_TYPE, -1) == TYPE_MOBILE_SUPL);
mCm.requestNetwork(legacyRequest, callback);
callback.expectCallback(CallbackEntry.AVAILABLE, mCellNetworkAgent);
- waitFor(cv2);
-
- // File another request, withdraw it and make sure no broadcast is sent
- final ConditionVariable cv3 = registerConnectivityBroadcast(1);
- final TestNetworkCallback callback2 = new TestNetworkCallback();
- mCm.requestNetwork(legacyRequest, callback2);
- callback2.expectCallback(CallbackEntry.AVAILABLE, mCellNetworkAgent);
- mCm.unregisterNetworkCallback(callback2);
- assertFalse(cv3.block(800)); // 800ms long enough to at least flake if this is sent
+ mCm.unregisterNetworkCallback(callback);
+ assertFalse(cv2.block(800)); // 800ms long enough to at least flake if this is sent
// As the broadcast did not fire, the receiver was not unregistered. Do this now.
mServiceContext.clearRegisteredReceivers();
- // Withdraw the request and check that the broadcast for disconnection is sent.
- final ConditionVariable cv4 = registerConnectivityBroadcastThat(1, intent ->
- !((NetworkInfo) intent.getExtra(EXTRA_NETWORK_INFO, -1)).isConnected()
- && intent.getIntExtra(EXTRA_NETWORK_TYPE, -1) == TYPE_MOBILE_SUPL);
- mCm.unregisterNetworkCallback(callback);
- waitFor(cv4);
-
- // Re-file the request and expect the connected broadcast again
- final ConditionVariable cv5 = registerConnectivityBroadcastThat(1,
- intent -> intent.getIntExtra(EXTRA_NETWORK_TYPE, -1) == TYPE_MOBILE_SUPL);
- final TestNetworkCallback callback3 = new TestNetworkCallback();
- mCm.requestNetwork(legacyRequest, callback3);
- callback3.expectCallback(CallbackEntry.AVAILABLE, mCellNetworkAgent);
- waitFor(cv5);
-
- // Disconnect the network and expect two disconnected broadcasts, one for SUPL and one
- // for mobile. Use a small hack to check that both have been sent, but the order is
- // not contractual.
+ // Disconnect the network and expect mobile disconnected broadcast. Use a small hack to
+ // check that has been sent.
final AtomicBoolean vanillaAction = new AtomicBoolean(false);
- final AtomicBoolean suplAction = new AtomicBoolean(false);
- final ConditionVariable cv6 = registerConnectivityBroadcastThat(2, intent -> {
+ final ConditionVariable cv3 = registerConnectivityBroadcastThat(1, intent -> {
if (intent.getAction().equals(CONNECTIVITY_ACTION)) {
vanillaAction.set(true);
- } else if (intent.getAction().equals(CONNECTIVITY_ACTION_SUPL)) {
- suplAction.set(true);
}
return !((NetworkInfo) intent.getExtra(EXTRA_NETWORK_INFO, -1)).isConnected();
});
mCellNetworkAgent.disconnect();
- waitFor(cv6);
+ waitFor(cv3);
assertTrue(vanillaAction.get());
- assertTrue(suplAction.get());
}
@Test
@@ -2464,8 +2434,8 @@
final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
mServiceContext, "testFactory", filter);
// Register the factory and don't be surprised when the default request arrives.
- testFactory.register();
testFactory.expectAddRequestsWithScores(0);
+ testFactory.register();
testFactory.waitForNetworkRequests(1);
testFactory.setScoreFilter(42);
@@ -6064,6 +6034,7 @@
verify(mBatteryStatsService).noteNetworkInterfaceType(stackedLp.getInterfaceName(),
TYPE_MOBILE);
}
+ reset(mMockNetd);
// Add ipv4 address, expect that clatd and prefix discovery are stopped and stacked
// linkproperties are cleaned up.
@@ -6115,7 +6086,6 @@
networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
verify(mMockNetd, times(1)).clatdStart(MOBILE_IFNAME, kNat64Prefix.toString());
-
// Clat iface comes up. Expect stacked link to be added.
clat.interfaceLinkStateChanged(CLAT_PREFIX + MOBILE_IFNAME, true);
networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
@@ -6701,17 +6671,45 @@
}
}
+ private void assertRouteInfoParcelMatches(RouteInfo route, RouteInfoParcel parcel) {
+ assertEquals(route.getDestination().toString(), parcel.destination);
+ assertEquals(route.getInterface(), parcel.ifName);
+ assertEquals(route.getMtu(), parcel.mtu);
+
+ switch (route.getType()) {
+ case RouteInfo.RTN_UNICAST:
+ if (route.hasGateway()) {
+ assertEquals(route.getGateway().getHostAddress(), parcel.nextHop);
+ } else {
+ assertEquals(INetd.NEXTHOP_NONE, parcel.nextHop);
+ }
+ break;
+ case RouteInfo.RTN_UNREACHABLE:
+ assertEquals(INetd.NEXTHOP_UNREACHABLE, parcel.nextHop);
+ break;
+ case RouteInfo.RTN_THROW:
+ assertEquals(INetd.NEXTHOP_THROW, parcel.nextHop);
+ break;
+ default:
+ assertEquals(INetd.NEXTHOP_NONE, parcel.nextHop);
+ break;
+ }
+ }
+
private void assertRoutesAdded(int netId, RouteInfo... routes) throws Exception {
- InOrder inOrder = inOrder(mNetworkManagementService);
+ ArgumentCaptor<RouteInfoParcel> captor = ArgumentCaptor.forClass(RouteInfoParcel.class);
+ verify(mMockNetd, times(routes.length)).networkAddRouteParcel(eq(netId), captor.capture());
for (int i = 0; i < routes.length; i++) {
- inOrder.verify(mNetworkManagementService).addRoute(eq(netId), eq(routes[i]));
+ assertRouteInfoParcelMatches(routes[i], captor.getAllValues().get(i));
}
}
private void assertRoutesRemoved(int netId, RouteInfo... routes) throws Exception {
- InOrder inOrder = inOrder(mNetworkManagementService);
+ ArgumentCaptor<RouteInfoParcel> captor = ArgumentCaptor.forClass(RouteInfoParcel.class);
+ verify(mMockNetd, times(routes.length)).networkRemoveRouteParcel(eq(netId),
+ captor.capture());
for (int i = 0; i < routes.length; i++) {
- inOrder.verify(mNetworkManagementService).removeRoute(eq(netId), eq(routes[i]));
+ assertRouteInfoParcelMatches(routes[i], captor.getAllValues().get(i));
}
}
@@ -6851,7 +6849,7 @@
@Test
public void testCheckConnectivityDiagnosticsPermissionsNetworkAdministrator() throws Exception {
final NetworkCapabilities nc = new NetworkCapabilities();
- nc.setAdministratorUids(Arrays.asList(Process.myUid()));
+ nc.setAdministratorUids(new int[] {Process.myUid()});
final NetworkAgentInfo naiWithUid =
new NetworkAgentInfo(
null, null, null, null, null, nc, 0, mServiceContext, null, null,
@@ -6873,7 +6871,7 @@
public void testCheckConnectivityDiagnosticsPermissionsFails() throws Exception {
final NetworkCapabilities nc = new NetworkCapabilities();
nc.setOwnerUid(Process.myUid());
- nc.setAdministratorUids(Arrays.asList(Process.myUid()));
+ nc.setAdministratorUids(new int[] {Process.myUid()});
final NetworkAgentInfo naiWithUid =
new NetworkAgentInfo(
null, null, null, null, null, nc, 0, mServiceContext, null, null,
@@ -6926,7 +6924,7 @@
argThat(report -> {
final NetworkCapabilities nc = report.getNetworkCapabilities();
return nc.getUids() == null
- && nc.getAdministratorUids().isEmpty()
+ && nc.getAdministratorUids().length == 0
&& nc.getOwnerUid() == Process.INVALID_UID;
}));
}
@@ -6947,7 +6945,7 @@
argThat(report -> {
final NetworkCapabilities nc = report.getNetworkCapabilities();
return nc.getUids() == null
- && nc.getAdministratorUids().isEmpty()
+ && nc.getAdministratorUids().length == 0
&& nc.getOwnerUid() == Process.INVALID_UID;
}));
}
@@ -6977,4 +6975,60 @@
verify(mConnectivityDiagnosticsCallback)
.onNetworkConnectivityReported(eq(n), eq(noConnectivity));
}
+
+ @Test
+ public void testRouteAddDeleteUpdate() throws Exception {
+ final NetworkRequest request = new NetworkRequest.Builder().build();
+ final TestNetworkCallback networkCallback = new TestNetworkCallback();
+ mCm.registerNetworkCallback(request, networkCallback);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ reset(mMockNetd);
+ mCellNetworkAgent.connect(false);
+ networkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
+ final int netId = mCellNetworkAgent.getNetwork().netId;
+
+ final String iface = "rmnet_data0";
+ final InetAddress gateway = InetAddress.getByName("fe80::5678");
+ RouteInfo direct = RouteInfo.makeHostRoute(gateway, iface);
+ RouteInfo rio1 = new RouteInfo(new IpPrefix("2001:db8:1::/48"), gateway, iface);
+ RouteInfo rio2 = new RouteInfo(new IpPrefix("2001:db8:2::/48"), gateway, iface);
+ RouteInfo defaultRoute = new RouteInfo((IpPrefix) null, gateway, iface);
+ RouteInfo defaultWithMtu = new RouteInfo(null, gateway, iface, RouteInfo.RTN_UNICAST,
+ 1280 /* mtu */);
+
+ // Send LinkProperties and check that we ask netd to add routes.
+ LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName(iface);
+ lp.addRoute(direct);
+ lp.addRoute(rio1);
+ lp.addRoute(defaultRoute);
+ mCellNetworkAgent.sendLinkProperties(lp);
+ networkCallback.expectLinkPropertiesThat(mCellNetworkAgent, x -> x.getRoutes().size() == 3);
+
+ assertRoutesAdded(netId, direct, rio1, defaultRoute);
+ reset(mMockNetd);
+
+ // Send updated LinkProperties and check that we ask netd to add, remove, update routes.
+ assertTrue(lp.getRoutes().contains(defaultRoute));
+ lp.removeRoute(rio1);
+ lp.addRoute(rio2);
+ lp.addRoute(defaultWithMtu);
+ // Ensure adding the same route with a different MTU replaces the previous route.
+ assertFalse(lp.getRoutes().contains(defaultRoute));
+ assertTrue(lp.getRoutes().contains(defaultWithMtu));
+
+ mCellNetworkAgent.sendLinkProperties(lp);
+ networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
+ x -> x.getRoutes().contains(rio2));
+
+ assertRoutesRemoved(netId, rio1);
+ assertRoutesAdded(netId, rio2);
+
+ ArgumentCaptor<RouteInfoParcel> captor = ArgumentCaptor.forClass(RouteInfoParcel.class);
+ verify(mMockNetd).networkUpdateRouteParcel(eq(netId), captor.capture());
+ assertRouteInfoParcelMatches(defaultWithMtu, captor.getValue());
+
+
+ mCm.unregisterNetworkCallback(networkCallback);
+ }
}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
index 8f90f13..551498f 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
@@ -319,33 +319,33 @@
assertEntry(18322, 75, 15031, 75, history.getValues(i++, null));
assertEntry(527798, 761, 78570, 652, history.getValues(i++, null));
assertEntry(527797, 760, 78570, 651, history.getValues(i++, null));
- assertEntry(10747, 50, 16838, 55, history.getValues(i++, null));
- assertEntry(10747, 49, 16838, 54, history.getValues(i++, null));
+ assertEntry(10747, 50, 16839, 55, history.getValues(i++, null));
+ assertEntry(10747, 49, 16837, 54, history.getValues(i++, null));
assertEntry(89191, 151, 18021, 140, history.getValues(i++, null));
assertEntry(89190, 150, 18020, 139, history.getValues(i++, null));
- assertEntry(3821, 22, 4525, 26, history.getValues(i++, null));
- assertEntry(3820, 22, 4524, 26, history.getValues(i++, null));
- assertEntry(91686, 159, 18575, 146, history.getValues(i++, null));
- assertEntry(91685, 159, 18575, 146, history.getValues(i++, null));
- assertEntry(8289, 35, 6863, 38, history.getValues(i++, null));
- assertEntry(8289, 35, 6863, 38, history.getValues(i++, null));
+ assertEntry(3821, 23, 4525, 26, history.getValues(i++, null));
+ assertEntry(3820, 21, 4524, 26, history.getValues(i++, null));
+ assertEntry(91686, 159, 18576, 146, history.getValues(i++, null));
+ assertEntry(91685, 159, 18574, 146, history.getValues(i++, null));
+ assertEntry(8289, 36, 6864, 39, history.getValues(i++, null));
+ assertEntry(8289, 34, 6862, 37, history.getValues(i++, null));
assertEntry(113914, 174, 18364, 157, history.getValues(i++, null));
assertEntry(113913, 173, 18364, 157, history.getValues(i++, null));
- assertEntry(11378, 49, 9261, 49, history.getValues(i++, null));
- assertEntry(11377, 48, 9261, 49, history.getValues(i++, null));
- assertEntry(201765, 328, 41808, 291, history.getValues(i++, null));
- assertEntry(201765, 328, 41807, 290, history.getValues(i++, null));
- assertEntry(106106, 218, 39917, 201, history.getValues(i++, null));
- assertEntry(106105, 217, 39917, 201, history.getValues(i++, null));
+ assertEntry(11378, 49, 9261, 50, history.getValues(i++, null));
+ assertEntry(11377, 48, 9261, 48, history.getValues(i++, null));
+ assertEntry(201766, 328, 41808, 291, history.getValues(i++, null));
+ assertEntry(201764, 328, 41807, 290, history.getValues(i++, null));
+ assertEntry(106106, 219, 39918, 202, history.getValues(i++, null));
+ assertEntry(106105, 216, 39916, 200, history.getValues(i++, null));
assertEquals(history.size(), i);
// Slice from middle should be untouched
history = getHistory(collection, plan, TIME_B - HOUR_IN_MILLIS,
TIME_B + HOUR_IN_MILLIS); i = 0;
- assertEntry(3821, 22, 4525, 26, history.getValues(i++, null));
- assertEntry(3820, 22, 4524, 26, history.getValues(i++, null));
- assertEntry(91686, 159, 18575, 146, history.getValues(i++, null));
- assertEntry(91685, 159, 18575, 146, history.getValues(i++, null));
+ assertEntry(3821, 23, 4525, 26, history.getValues(i++, null));
+ assertEntry(3820, 21, 4524, 26, history.getValues(i++, null));
+ assertEntry(91686, 159, 18576, 146, history.getValues(i++, null));
+ assertEntry(91685, 159, 18574, 146, history.getValues(i++, null));
assertEquals(history.size(), i);
}
@@ -373,25 +373,25 @@
assertEntry(527797, 760, 78570, 651, history.getValues(i++, null));
// Cycle point; start data normalization
assertEntry(7507, 0, 11763, 0, history.getValues(i++, null));
- assertEntry(7507, 0, 11763, 0, history.getValues(i++, null));
+ assertEntry(7507, 0, 11762, 0, history.getValues(i++, null));
assertEntry(62309, 0, 12589, 0, history.getValues(i++, null));
assertEntry(62309, 0, 12588, 0, history.getValues(i++, null));
assertEntry(2669, 0, 3161, 0, history.getValues(i++, null));
assertEntry(2668, 0, 3160, 0, history.getValues(i++, null));
// Anchor point; end data normalization
- assertEntry(91686, 159, 18575, 146, history.getValues(i++, null));
- assertEntry(91685, 159, 18575, 146, history.getValues(i++, null));
- assertEntry(8289, 35, 6863, 38, history.getValues(i++, null));
- assertEntry(8289, 35, 6863, 38, history.getValues(i++, null));
+ assertEntry(91686, 159, 18576, 146, history.getValues(i++, null));
+ assertEntry(91685, 159, 18574, 146, history.getValues(i++, null));
+ assertEntry(8289, 36, 6864, 39, history.getValues(i++, null));
+ assertEntry(8289, 34, 6862, 37, history.getValues(i++, null));
assertEntry(113914, 174, 18364, 157, history.getValues(i++, null));
assertEntry(113913, 173, 18364, 157, history.getValues(i++, null));
// Cycle point
- assertEntry(11378, 49, 9261, 49, history.getValues(i++, null));
- assertEntry(11377, 48, 9261, 49, history.getValues(i++, null));
- assertEntry(201765, 328, 41808, 291, history.getValues(i++, null));
- assertEntry(201765, 328, 41807, 290, history.getValues(i++, null));
- assertEntry(106106, 218, 39917, 201, history.getValues(i++, null));
- assertEntry(106105, 217, 39917, 201, history.getValues(i++, null));
+ assertEntry(11378, 49, 9261, 50, history.getValues(i++, null));
+ assertEntry(11377, 48, 9261, 48, history.getValues(i++, null));
+ assertEntry(201766, 328, 41808, 291, history.getValues(i++, null));
+ assertEntry(201764, 328, 41807, 290, history.getValues(i++, null));
+ assertEntry(106106, 219, 39918, 202, history.getValues(i++, null));
+ assertEntry(106105, 216, 39916, 200, history.getValues(i++, null));
assertEquals(history.size(), i);
// Slice from middle should be augmented
@@ -399,8 +399,8 @@
TIME_B + HOUR_IN_MILLIS); i = 0;
assertEntry(2669, 0, 3161, 0, history.getValues(i++, null));
assertEntry(2668, 0, 3160, 0, history.getValues(i++, null));
- assertEntry(91686, 159, 18575, 146, history.getValues(i++, null));
- assertEntry(91685, 159, 18575, 146, history.getValues(i++, null));
+ assertEntry(91686, 159, 18576, 146, history.getValues(i++, null));
+ assertEntry(91685, 159, 18574, 146, history.getValues(i++, null));
assertEquals(history.size(), i);
}
@@ -427,34 +427,34 @@
assertEntry(527798, 761, 78570, 652, history.getValues(i++, null));
assertEntry(527797, 760, 78570, 651, history.getValues(i++, null));
// Cycle point; start data normalization
- assertEntry(15015, 0, 23526, 0, history.getValues(i++, null));
- assertEntry(15015, 0, 23526, 0, history.getValues(i++, null));
+ assertEntry(15015, 0, 23527, 0, history.getValues(i++, null));
+ assertEntry(15015, 0, 23524, 0, history.getValues(i++, null));
assertEntry(124619, 0, 25179, 0, history.getValues(i++, null));
assertEntry(124618, 0, 25177, 0, history.getValues(i++, null));
assertEntry(5338, 0, 6322, 0, history.getValues(i++, null));
assertEntry(5337, 0, 6320, 0, history.getValues(i++, null));
// Anchor point; end data normalization
- assertEntry(91686, 159, 18575, 146, history.getValues(i++, null));
- assertEntry(91685, 159, 18575, 146, history.getValues(i++, null));
- assertEntry(8289, 35, 6863, 38, history.getValues(i++, null));
- assertEntry(8289, 35, 6863, 38, history.getValues(i++, null));
+ assertEntry(91686, 159, 18576, 146, history.getValues(i++, null));
+ assertEntry(91685, 159, 18574, 146, history.getValues(i++, null));
+ assertEntry(8289, 36, 6864, 39, history.getValues(i++, null));
+ assertEntry(8289, 34, 6862, 37, history.getValues(i++, null));
assertEntry(113914, 174, 18364, 157, history.getValues(i++, null));
assertEntry(113913, 173, 18364, 157, history.getValues(i++, null));
// Cycle point
- assertEntry(11378, 49, 9261, 49, history.getValues(i++, null));
- assertEntry(11377, 48, 9261, 49, history.getValues(i++, null));
- assertEntry(201765, 328, 41808, 291, history.getValues(i++, null));
- assertEntry(201765, 328, 41807, 290, history.getValues(i++, null));
- assertEntry(106106, 218, 39917, 201, history.getValues(i++, null));
- assertEntry(106105, 217, 39917, 201, history.getValues(i++, null));
+ assertEntry(11378, 49, 9261, 50, history.getValues(i++, null));
+ assertEntry(11377, 48, 9261, 48, history.getValues(i++, null));
+ assertEntry(201766, 328, 41808, 291, history.getValues(i++, null));
+ assertEntry(201764, 328, 41807, 290, history.getValues(i++, null));
+ assertEntry(106106, 219, 39918, 202, history.getValues(i++, null));
+ assertEntry(106105, 216, 39916, 200, history.getValues(i++, null));
// Slice from middle should be augmented
history = getHistory(collection, plan, TIME_B - HOUR_IN_MILLIS,
TIME_B + HOUR_IN_MILLIS); i = 0;
assertEntry(5338, 0, 6322, 0, history.getValues(i++, null));
assertEntry(5337, 0, 6320, 0, history.getValues(i++, null));
- assertEntry(91686, 159, 18575, 146, history.getValues(i++, null));
- assertEntry(91685, 159, 18575, 146, history.getValues(i++, null));
+ assertEntry(91686, 159, 18576, 146, history.getValues(i++, null));
+ assertEntry(91685, 159, 18574, 146, history.getValues(i++, null));
assertEquals(history.size(), i);
}
}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index b346c92..6e63313 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -42,6 +42,7 @@
import static android.net.NetworkStats.UID_ALL;
import static android.net.NetworkStatsHistory.FIELD_ALL;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
+import static android.net.NetworkTemplate.buildTemplateMobileWithRatType;
import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
import static android.net.TrafficStats.MB_IN_BYTES;
import static android.net.TrafficStats.UID_REMOVED;
@@ -60,11 +61,13 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.AlarmManager;
import android.app.usage.NetworkStatsManager;
import android.content.Context;
@@ -92,6 +95,8 @@
import android.os.Messenger;
import android.os.PowerManager;
import android.os.SimpleClock;
+import android.telephony.PhoneStateListener;
+import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import androidx.test.InstrumentationRegistry;
@@ -163,11 +168,14 @@
private @Mock NetworkStatsSettings mSettings;
private @Mock IBinder mBinder;
private @Mock AlarmManager mAlarmManager;
+ private @Mock TelephonyManager mTelephonyManager;
private HandlerThread mHandlerThread;
private NetworkStatsService mService;
private INetworkStatsSession mSession;
private INetworkManagementEventObserver mNetworkObserver;
+ @Nullable
+ private PhoneStateListener mPhoneStateListener;
private final Clock mClock = new SimpleClock(ZoneOffset.UTC) {
@Override
@@ -195,7 +203,7 @@
mHandlerThread = new HandlerThread("HandlerThread");
final NetworkStatsService.Dependencies deps = makeDependencies();
mService = new NetworkStatsService(mServiceContext, mNetManager, mAlarmManager, wakeLock,
- mClock, mServiceContext.getSystemService(TelephonyManager.class), mSettings,
+ mClock, mTelephonyManager, mSettings,
mStatsFactory, new NetworkStatsObservers(), mStatsDir, getBaseDir(mStatsDir), deps);
mElapsedRealtime = 0L;
@@ -216,6 +224,12 @@
ArgumentCaptor.forClass(INetworkManagementEventObserver.class);
verify(mNetManager).registerObserver(networkObserver.capture());
mNetworkObserver = networkObserver.getValue();
+
+ // Capture the phone state listener that created by service.
+ final ArgumentCaptor<PhoneStateListener> phoneStateListenerCaptor =
+ ArgumentCaptor.forClass(PhoneStateListener.class);
+ verify(mTelephonyManager).listen(phoneStateListenerCaptor.capture(), anyInt());
+ mPhoneStateListener = phoneStateListenerCaptor.getValue();
}
@NonNull
@@ -534,7 +548,7 @@
}
@Test
- public void testUid3g4gCombinedByTemplate() throws Exception {
+ public void testUid3gWimaxCombinedByTemplate() throws Exception {
// pretend that network comes online
expectDefaultSettings();
NetworkState[] states = new NetworkState[] {buildMobile3gState(IMSI_1)};
@@ -558,10 +572,10 @@
assertUidTotal(sTemplateImsi1, UID_RED, 1024L, 8L, 1024L, 8L, 5);
- // now switch over to 4g network
+ // now switch over to wimax network
incrementCurrentTime(HOUR_IN_MILLIS);
expectDefaultSettings();
- states = new NetworkState[] {buildMobile4gState(TEST_IFACE2)};
+ states = new NetworkState[] {buildWimaxState(TEST_IFACE2)};
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L)
@@ -589,6 +603,89 @@
}
@Test
+ public void testMobileStatsByRatType() throws Exception {
+ final NetworkTemplate template3g =
+ buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UMTS);
+ final NetworkTemplate template4g =
+ buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_LTE);
+ final NetworkTemplate template5g =
+ buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_NR);
+ final NetworkState[] states = new NetworkState[]{buildMobile3gState(IMSI_1)};
+
+ // 3G network comes online.
+ expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(buildEmptyStats());
+
+ setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_UMTS);
+ mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+ new VpnInfo[0]);
+
+ // Create some traffic.
+ incrementCurrentTime(MINUTE_IN_MILLIS);
+ expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
+ 12L, 18L, 14L, 1L, 0L)));
+ forcePollAndWaitForIdle();
+
+ // Verify 3g templates gets stats.
+ assertUidTotal(sTemplateImsi1, UID_RED, 12L, 18L, 14L, 1L, 0);
+ assertUidTotal(template3g, UID_RED, 12L, 18L, 14L, 1L, 0);
+ assertUidTotal(template4g, UID_RED, 0L, 0L, 0L, 0L, 0);
+ assertUidTotal(template5g, UID_RED, 0L, 0L, 0L, 0L, 0);
+
+ // 4G network comes online.
+ incrementCurrentTime(MINUTE_IN_MILLIS);
+ setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_LTE);
+ expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ // Append more traffic on existing 3g stats entry.
+ .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
+ 16L, 22L, 17L, 2L, 0L))
+ // Add entry that is new on 4g.
+ .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE,
+ 33L, 27L, 8L, 10L, 1L)));
+ forcePollAndWaitForIdle();
+
+ // Verify ALL_MOBILE template gets all. 3g template counters do not increase.
+ assertUidTotal(sTemplateImsi1, UID_RED, 49L, 49L, 25L, 12L, 1);
+ assertUidTotal(template3g, UID_RED, 12L, 18L, 14L, 1L, 0);
+ // Verify 4g template counts appended stats on existing entry and newly created entry.
+ assertUidTotal(template4g, UID_RED, 4L + 33L, 4L + 27L, 3L + 8L, 1L + 10L, 1);
+ // Verify 5g template doesn't get anything since no traffic is generated on 5g.
+ assertUidTotal(template5g, UID_RED, 0L, 0L, 0L, 0L, 0);
+
+ // 5g network comes online.
+ incrementCurrentTime(MINUTE_IN_MILLIS);
+ setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_NR);
+ expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ // Existing stats remains.
+ .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
+ 16L, 22L, 17L, 2L, 0L))
+ .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE,
+ 33L, 27L, 8L, 10L, 1L))
+ // Add some traffic on 5g.
+ .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
+ 5L, 13L, 31L, 9L, 2L)));
+ forcePollAndWaitForIdle();
+
+ // Verify ALL_MOBILE template gets all.
+ assertUidTotal(sTemplateImsi1, UID_RED, 54L, 62L, 56L, 21L, 3);
+ // 3g/4g template counters do not increase.
+ assertUidTotal(template3g, UID_RED, 12L, 18L, 14L, 1L, 0);
+ assertUidTotal(template4g, UID_RED, 4L + 33L, 4L + 27L, 3L + 8L, 1L + 10L, 1);
+ // Verify 5g template gets the 5g count.
+ assertUidTotal(template5g, UID_RED, 5L, 13L, 31L, 9L, 2);
+ }
+
+ // TODO: support per IMSI state
+ private void setMobileRatTypeAndWaitForIdle(int ratType) {
+ final ServiceState mockSs = mock(ServiceState.class);
+ when(mockSs.getDataNetworkType()).thenReturn(ratType);
+ mPhoneStateListener.onServiceStateChanged(mockSs);
+
+ HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT);
+ }
+
+ @Test
public void testSummaryForAllUid() throws Exception {
// pretend that network comes online
expectDefaultSettings();
@@ -1197,6 +1294,7 @@
when(mSettings.getPollInterval()).thenReturn(HOUR_IN_MILLIS);
when(mSettings.getPollDelay()).thenReturn(0L);
when(mSettings.getSampleEnabled()).thenReturn(true);
+ when(mSettings.getCombineSubtypeEnabled()).thenReturn(false);
final Config config = new Config(bucketDuration, deleteAge, deleteAge);
when(mSettings.getDevConfig()).thenReturn(config);
@@ -1242,6 +1340,7 @@
final NetworkCapabilities capabilities = new NetworkCapabilities();
capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, !isMetered);
capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true);
+ capabilities.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
return new NetworkState(info, prop, capabilities, WIFI_NETWORK, null, TEST_SSID);
}
@@ -1259,10 +1358,11 @@
final NetworkCapabilities capabilities = new NetworkCapabilities();
capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false);
capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, !isRoaming);
+ capabilities.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
return new NetworkState(info, prop, capabilities, MOBILE_NETWORK, subscriberId, null);
}
- private static NetworkState buildMobile4gState(String iface) {
+ private static NetworkState buildWimaxState(@NonNull String iface) {
final NetworkInfo info = new NetworkInfo(TYPE_WIMAX, 0, null, null);
info.setDetailedState(DetailedState.CONNECTED, null, null);
final LinkProperties prop = new LinkProperties();