Move module sources to packages/Connectivity
Files that are planned to be part of the connectivity module are grouped
in packages/Connectivity, so they can be built separately and moved in
one operation with their history into packages/modules/Connectivity.
This places the files in the existing framework-connectivity-sources
filegroup instead of the current framework-core-sources filegroup. Both
are used the same way in framework-non-updatable-sources.
Bug: 171540887
Test: m
Change-Id: I62d9d91574ace6f5c4624035d190260c3126b91e
diff --git a/framework/src/android/net/RouteInfo.java b/framework/src/android/net/RouteInfo.java
new file mode 100644
index 0000000..94f849f
--- /dev/null
+++ b/framework/src/android/net/RouteInfo.java
@@ -0,0 +1,658 @@
+/*
+ * Copyright (C) 2011 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.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.compat.annotation.UnsupportedAppUsage;
+import android.os.Build;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.net.module.util.NetUtils;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Collection;
+import java.util.Objects;
+
+/**
+ * Represents a network route.
+ * <p>
+ * This is used both to describe static network configuration and live network
+ * configuration information.
+ *
+ * A route contains three pieces of information:
+ * <ul>
+ * <li>a destination {@link IpPrefix} specifying the network destinations covered by this route.
+ * If this is {@code null} it indicates a default route of the address family (IPv4 or IPv6)
+ * implied by the gateway IP address.
+ * <li>a gateway {@link InetAddress} indicating the next hop to use. If this is {@code null} it
+ * indicates a directly-connected route.
+ * <li>an interface (which may be unspecified).
+ * </ul>
+ * Either the destination or the gateway may be {@code null}, but not both. If the
+ * destination and gateway are both specified, they must be of the same address family
+ * (IPv4 or IPv6).
+ */
+public final class RouteInfo implements Parcelable {
+ /** @hide */
+ @IntDef(value = {
+ RTN_UNICAST,
+ RTN_UNREACHABLE,
+ RTN_THROW,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface RouteType {}
+
+ /**
+ * The IP destination address for this route.
+ */
+ @NonNull
+ private final IpPrefix mDestination;
+
+ /**
+ * The gateway address for this route.
+ */
+ @UnsupportedAppUsage
+ @Nullable
+ private final InetAddress mGateway;
+
+ /**
+ * The interface for this route.
+ */
+ @Nullable
+ private final String mInterface;
+
+
+ /** Unicast route. @hide */
+ @SystemApi
+ public static final int RTN_UNICAST = 1;
+
+ /** Unreachable route. @hide */
+ @SystemApi
+ public static final int RTN_UNREACHABLE = 7;
+
+ /** Throw route. @hide */
+ @SystemApi
+ public static final int RTN_THROW = 9;
+
+ /**
+ * The type of this route; one of the RTN_xxx constants above.
+ */
+ private final int mType;
+
+ /**
+ * The maximum transmission unit size for this route.
+ */
+ private final int mMtu;
+
+ // Derived data members.
+ // TODO: remove these.
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+ private final boolean mIsHost;
+ private final boolean mHasGateway;
+
+ /**
+ * Constructs a RouteInfo object.
+ *
+ * If destination is null, then gateway must be specified and the
+ * constructed route is either the IPv4 default route <code>0.0.0.0</code>
+ * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default
+ * route <code>::/0</code> if gateway is an instance of
+ * {@link Inet6Address}.
+ * <p>
+ * destination and gateway may not both be null.
+ *
+ * @param destination the destination prefix
+ * @param gateway the IP address to route packets through
+ * @param iface the interface name to send packets on
+ * @param type the type of this route
+ *
+ * @hide
+ */
+ @SystemApi
+ public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway,
+ @Nullable String iface, @RouteType int type) {
+ this(destination, gateway, iface, type, 0);
+ }
+
+ /**
+ * Constructs a RouteInfo object.
+ *
+ * If destination is null, then gateway must be specified and the
+ * constructed route is either the IPv4 default route <code>0.0.0.0</code>
+ * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default
+ * route <code>::/0</code> if gateway is an instance of
+ * {@link Inet6Address}.
+ * <p>
+ * destination and gateway may not both be null.
+ *
+ * @param destination the destination prefix
+ * @param gateway the IP address to route packets through
+ * @param iface the interface name to send packets on
+ * @param type the type of this route
+ * @param mtu the maximum transmission unit size for this route
+ *
+ * @hide
+ */
+ @SystemApi
+ public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway,
+ @Nullable String iface, @RouteType int type, int mtu) {
+ switch (type) {
+ case RTN_UNICAST:
+ case RTN_UNREACHABLE:
+ case RTN_THROW:
+ // TODO: It would be nice to ensure that route types that don't have nexthops or
+ // interfaces, such as unreachable or throw, can't be created if an interface or
+ // a gateway is specified. This is a bit too complicated to do at the moment
+ // because:
+ //
+ // - LinkProperties sets the interface on routes added to it, and modifies the
+ // interfaces of all the routes when its interface name changes.
+ // - Even when the gateway is null, we store a non-null gateway here.
+ //
+ // For now, we just rely on the code that sets routes to do things properly.
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown route type " + type);
+ }
+
+ if (destination == null) {
+ if (gateway != null) {
+ if (gateway instanceof Inet4Address) {
+ destination = new IpPrefix(Inet4Address.ANY, 0);
+ } else {
+ destination = new IpPrefix(Inet6Address.ANY, 0);
+ }
+ } else {
+ // no destination, no gateway. invalid.
+ throw new IllegalArgumentException("Invalid arguments passed in: " + gateway + "," +
+ destination);
+ }
+ }
+ // TODO: set mGateway to null if there is no gateway. This is more correct, saves space, and
+ // matches the documented behaviour. Before we can do this we need to fix all callers (e.g.,
+ // ConnectivityService) to stop doing things like r.getGateway().equals(), ... .
+ if (gateway == null) {
+ if (destination.getAddress() instanceof Inet4Address) {
+ gateway = Inet4Address.ANY;
+ } else {
+ gateway = Inet6Address.ANY;
+ }
+ }
+ mHasGateway = (!gateway.isAnyLocalAddress());
+
+ if ((destination.getAddress() instanceof Inet4Address
+ && !(gateway instanceof Inet4Address))
+ || (destination.getAddress() instanceof Inet6Address
+ && !(gateway instanceof Inet6Address))) {
+ throw new IllegalArgumentException("address family mismatch in RouteInfo constructor");
+ }
+ mDestination = destination; // IpPrefix objects are immutable.
+ mGateway = gateway; // InetAddress objects are immutable.
+ mInterface = iface; // Strings are immutable.
+ mType = type;
+ mIsHost = isHost();
+ mMtu = mtu;
+ }
+
+ /**
+ * Constructs a {@code RouteInfo} object.
+ *
+ * If destination is null, then gateway must be specified and the
+ * constructed route is either the IPv4 default route <code>0.0.0.0</code>
+ * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default
+ * route <code>::/0</code> if gateway is an instance of {@link Inet6Address}.
+ * <p>
+ * Destination and gateway may not both be null.
+ *
+ * @param destination the destination address and prefix in an {@link IpPrefix}
+ * @param gateway the {@link InetAddress} to route packets through
+ * @param iface the interface name to send packets on
+ *
+ * @hide
+ */
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway,
+ @Nullable String iface) {
+ this(destination, gateway, iface, RTN_UNICAST);
+ }
+
+ /**
+ * @hide
+ */
+ @UnsupportedAppUsage
+ public RouteInfo(@Nullable LinkAddress destination, @Nullable InetAddress gateway,
+ @Nullable String iface) {
+ this(destination == null ? null :
+ new IpPrefix(destination.getAddress(), destination.getPrefixLength()),
+ gateway, iface);
+ }
+
+ /**
+ * Constructs a {@code RouteInfo} object.
+ *
+ * If destination is null, then gateway must be specified and the
+ * constructed route is either the IPv4 default route <code>0.0.0.0</code>
+ * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default
+ * route <code>::/0</code> if gateway is an instance of {@link Inet6Address}.
+ * <p>
+ * Destination and gateway may not both be null.
+ *
+ * @param destination the destination address and prefix in an {@link IpPrefix}
+ * @param gateway the {@link InetAddress} to route packets through
+ *
+ * @hide
+ */
+ public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway) {
+ this(destination, gateway, null);
+ }
+
+ /**
+ * @hide
+ *
+ * TODO: Remove this.
+ */
+ @UnsupportedAppUsage
+ public RouteInfo(@Nullable LinkAddress destination, @Nullable InetAddress gateway) {
+ this(destination, gateway, null);
+ }
+
+ /**
+ * Constructs a default {@code RouteInfo} object.
+ *
+ * @param gateway the {@link InetAddress} to route packets through
+ *
+ * @hide
+ */
+ @UnsupportedAppUsage
+ public RouteInfo(@NonNull InetAddress gateway) {
+ this((IpPrefix) null, gateway, null);
+ }
+
+ /**
+ * Constructs a {@code RouteInfo} object representing a direct connected subnet.
+ *
+ * @param destination the {@link IpPrefix} describing the address and prefix
+ * length of the subnet.
+ *
+ * @hide
+ */
+ public RouteInfo(@NonNull IpPrefix destination) {
+ this(destination, null, null);
+ }
+
+ /**
+ * @hide
+ */
+ public RouteInfo(@NonNull LinkAddress destination) {
+ this(destination, null, null);
+ }
+
+ /**
+ * @hide
+ */
+ public RouteInfo(@NonNull IpPrefix destination, @RouteType int type) {
+ this(destination, null, null, type);
+ }
+
+ /**
+ * @hide
+ */
+ public static RouteInfo makeHostRoute(@NonNull InetAddress host, @Nullable String iface) {
+ return makeHostRoute(host, null, iface);
+ }
+
+ /**
+ * @hide
+ */
+ public static RouteInfo makeHostRoute(@Nullable InetAddress host, @Nullable InetAddress gateway,
+ @Nullable String iface) {
+ if (host == null) return null;
+
+ if (host instanceof Inet4Address) {
+ return new RouteInfo(new IpPrefix(host, 32), gateway, iface);
+ } else {
+ return new RouteInfo(new IpPrefix(host, 128), gateway, iface);
+ }
+ }
+
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+ private boolean isHost() {
+ return (mDestination.getAddress() instanceof Inet4Address &&
+ mDestination.getPrefixLength() == 32) ||
+ (mDestination.getAddress() instanceof Inet6Address &&
+ mDestination.getPrefixLength() == 128);
+ }
+
+ /**
+ * Retrieves the destination address and prefix length in the form of an {@link IpPrefix}.
+ *
+ * @return {@link IpPrefix} specifying the destination. This is never {@code null}.
+ */
+ @NonNull
+ public IpPrefix getDestination() {
+ return mDestination;
+ }
+
+ /**
+ * TODO: Convert callers to use IpPrefix and then remove.
+ * @hide
+ */
+ @NonNull
+ public LinkAddress getDestinationLinkAddress() {
+ return new LinkAddress(mDestination.getAddress(), mDestination.getPrefixLength());
+ }
+
+ /**
+ * Retrieves the gateway or next hop {@link InetAddress} for this route.
+ *
+ * @return {@link InetAddress} specifying the gateway or next hop. This may be
+ * {@code null} for a directly-connected route."
+ */
+ @Nullable
+ public InetAddress getGateway() {
+ return mGateway;
+ }
+
+ /**
+ * Retrieves the interface used for this route if specified, else {@code null}.
+ *
+ * @return The name of the interface used for this route.
+ */
+ @Nullable
+ public String getInterface() {
+ return mInterface;
+ }
+
+ /**
+ * Retrieves the type of this route.
+ *
+ * @return The type of this route; one of the {@code RTN_xxx} constants defined in this class.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RouteType
+ public int getType() {
+ return mType;
+ }
+
+ /**
+ * Retrieves the MTU size for this route.
+ *
+ * @return The MTU size, or 0 if it has not been set.
+ * @hide
+ */
+ @SystemApi
+ public int getMtu() {
+ return mMtu;
+ }
+
+ /**
+ * Indicates if this route is a default route (ie, has no destination specified).
+ *
+ * @return {@code true} if the destination has a prefix length of 0.
+ */
+ public boolean isDefaultRoute() {
+ return mType == RTN_UNICAST && mDestination.getPrefixLength() == 0;
+ }
+
+ /**
+ * Indicates if this route is an unreachable default route.
+ *
+ * @return {@code true} if it's an unreachable route with prefix length of 0.
+ * @hide
+ */
+ private boolean isUnreachableDefaultRoute() {
+ return mType == RTN_UNREACHABLE && mDestination.getPrefixLength() == 0;
+ }
+
+ /**
+ * Indicates if this route is an IPv4 default route.
+ * @hide
+ */
+ public boolean isIPv4Default() {
+ return isDefaultRoute() && mDestination.getAddress() instanceof Inet4Address;
+ }
+
+ /**
+ * Indicates if this route is an IPv4 unreachable default route.
+ * @hide
+ */
+ public boolean isIPv4UnreachableDefault() {
+ return isUnreachableDefaultRoute() && mDestination.getAddress() instanceof Inet4Address;
+ }
+
+ /**
+ * Indicates if this route is an IPv6 default route.
+ * @hide
+ */
+ public boolean isIPv6Default() {
+ return isDefaultRoute() && mDestination.getAddress() instanceof Inet6Address;
+ }
+
+ /**
+ * Indicates if this route is an IPv6 unreachable default route.
+ * @hide
+ */
+ public boolean isIPv6UnreachableDefault() {
+ return isUnreachableDefaultRoute() && mDestination.getAddress() instanceof Inet6Address;
+ }
+
+ /**
+ * Indicates if this route is a host route (ie, matches only a single host address).
+ *
+ * @return {@code true} if the destination has a prefix length of 32 or 128 for IPv4 or IPv6,
+ * respectively.
+ * @hide
+ */
+ public boolean isHostRoute() {
+ return mIsHost;
+ }
+
+ /**
+ * Indicates if this route has a next hop ({@code true}) or is directly-connected
+ * ({@code false}).
+ *
+ * @return {@code true} if a gateway is specified
+ */
+ public boolean hasGateway() {
+ return mHasGateway;
+ }
+
+ /**
+ * Determines whether the destination and prefix of this route includes the specified
+ * address.
+ *
+ * @param destination A {@link InetAddress} to test to see if it would match this route.
+ * @return {@code true} if the destination and prefix length cover the given address.
+ */
+ public boolean matches(InetAddress destination) {
+ return mDestination.contains(destination);
+ }
+
+ /**
+ * Find the route from a Collection of routes that best matches a given address.
+ * May return null if no routes are applicable.
+ * @param routes a Collection of RouteInfos to chose from
+ * @param dest the InetAddress your trying to get to
+ * @return the RouteInfo from the Collection that best fits the given address
+ *
+ * @hide
+ */
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @Nullable
+ public static RouteInfo selectBestRoute(Collection<RouteInfo> routes, InetAddress dest) {
+ return NetUtils.selectBestRoute(routes, dest);
+ }
+
+ /**
+ * Returns a human-readable description of this object.
+ */
+ public String toString() {
+ String val = "";
+ if (mDestination != null) val = mDestination.toString();
+ if (mType == RTN_UNREACHABLE) {
+ val += " unreachable";
+ } else if (mType == RTN_THROW) {
+ val += " throw";
+ } else {
+ val += " ->";
+ if (mGateway != null) val += " " + mGateway.getHostAddress();
+ if (mInterface != null) val += " " + mInterface;
+ if (mType != RTN_UNICAST) {
+ val += " unknown type " + mType;
+ }
+ }
+ val += " mtu " + mMtu;
+ return val;
+ }
+
+ /**
+ * Compares this RouteInfo object against the specified object and indicates if they are equal.
+ * @return {@code true} if the objects are equal, {@code false} otherwise.
+ */
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+
+ if (!(obj instanceof RouteInfo)) return false;
+
+ RouteInfo target = (RouteInfo) obj;
+
+ return Objects.equals(mDestination, target.getDestination()) &&
+ Objects.equals(mGateway, target.getGateway()) &&
+ Objects.equals(mInterface, target.getInterface()) &&
+ mType == target.getType() && mMtu == target.getMtu();
+ }
+
+ /**
+ * A helper class that contains the destination, the gateway and the interface in a
+ * {@code RouteInfo}, used by {@link ConnectivityService#updateRoutes} or
+ * {@link LinkProperties#addRoute} to calculate the list to be updated.
+ * {@code RouteInfo} objects with different interfaces are treated as different routes because
+ * *usually* on Android different interfaces use different routing tables, and moving a route
+ * to a new routing table never constitutes an update, but is always a remove and an add.
+ *
+ * @hide
+ */
+ public static class RouteKey {
+ @NonNull private final IpPrefix mDestination;
+ @Nullable private final InetAddress mGateway;
+ @Nullable private final String mInterface;
+
+ RouteKey(@NonNull IpPrefix destination, @Nullable InetAddress gateway,
+ @Nullable String iface) {
+ mDestination = destination;
+ mGateway = gateway;
+ mInterface = iface;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof RouteKey)) {
+ return false;
+ }
+ RouteKey p = (RouteKey) o;
+ // No need to do anything special for scoped addresses. Inet6Address#equals does not
+ // consider the scope ID, but the netd route IPCs (e.g., INetd#networkAddRouteParcel)
+ // and the kernel ignore scoped addresses both in the prefix and in the nexthop and only
+ // look at RTA_OIF.
+ return Objects.equals(p.mDestination, mDestination)
+ && Objects.equals(p.mGateway, mGateway)
+ && Objects.equals(p.mInterface, mInterface);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mDestination, mGateway, mInterface);
+ }
+ }
+
+ /**
+ * Get {@code RouteKey} of this {@code RouteInfo}.
+ * @return a {@code RouteKey} object.
+ *
+ * @hide
+ */
+ @NonNull
+ public RouteKey getRouteKey() {
+ return new RouteKey(mDestination, mGateway, mInterface);
+ }
+
+ /**
+ * Returns a hashcode for this <code>RouteInfo</code> object.
+ */
+ public int hashCode() {
+ return (mDestination.hashCode() * 41)
+ + (mGateway == null ? 0 :mGateway.hashCode() * 47)
+ + (mInterface == null ? 0 :mInterface.hashCode() * 67)
+ + (mType * 71) + (mMtu * 89);
+ }
+
+ /**
+ * Implement the Parcelable interface
+ */
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Implement the Parcelable interface
+ */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(mDestination, flags);
+ byte[] gatewayBytes = (mGateway == null) ? null : mGateway.getAddress();
+ dest.writeByteArray(gatewayBytes);
+ dest.writeString(mInterface);
+ dest.writeInt(mType);
+ dest.writeInt(mMtu);
+ }
+
+ /**
+ * Implement the Parcelable interface.
+ */
+ public static final @android.annotation.NonNull Creator<RouteInfo> CREATOR =
+ new Creator<RouteInfo>() {
+ public RouteInfo createFromParcel(Parcel in) {
+ IpPrefix dest = in.readParcelable(null);
+
+ InetAddress gateway = null;
+ byte[] addr = in.createByteArray();
+ try {
+ gateway = InetAddress.getByAddress(addr);
+ } catch (UnknownHostException e) {}
+
+ String iface = in.readString();
+ int type = in.readInt();
+ int mtu = in.readInt();
+
+ return new RouteInfo(dest, gateway, iface, type, mtu);
+ }
+
+ public RouteInfo[] newArray(int size) {
+ return new RouteInfo[size];
+ }
+ };
+}