diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index ae93cf0197..6ba4a30abe 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1934,6 +1934,8 @@ public class ConnectivityManager { @NonNull Callback callback) { ParcelFileDescriptor dup; try { + // Dup is needed here as the pfd inside the socket is owned by the IpSecService, + // which cannot be obtained by the app process. dup = ParcelFileDescriptor.dup(socket.getFileDescriptor()); } catch (IOException ignored) { // Construct an invalid fd, so that if the user later calls start(), it will fail with @@ -1975,6 +1977,7 @@ public class ConnectivityManager { @NonNull Callback callback) { ParcelFileDescriptor dup; try { + // TODO: Consider remove unnecessary dup. dup = pfd.dup(); } catch (IOException ignored) { // Construct an invalid fd, so that if the user later calls start(), it will fail with @@ -3231,7 +3234,7 @@ public class ConnectivityManager { * * @hide */ - public void onPreCheck(Network network) {} + public void onPreCheck(@NonNull Network network) {} /** * Called when the framework connects and has declared a new network ready for use. @@ -3244,8 +3247,9 @@ public class ConnectivityManager { * @param blocked Whether access to the {@link Network} is blocked due to system policy. * @hide */ - public void onAvailable(Network network, NetworkCapabilities networkCapabilities, - LinkProperties linkProperties, boolean blocked) { + public void onAvailable(@NonNull Network network, + @NonNull NetworkCapabilities networkCapabilities, + @NonNull LinkProperties linkProperties, boolean blocked) { // Internally only this method is called when a new network is available, and // it calls the callback in the same way and order that older versions used // to call so as not to change the behavior. @@ -3269,7 +3273,7 @@ public class ConnectivityManager { * * @param network The {@link Network} of the satisfying network. */ - public void onAvailable(Network network) {} + public void onAvailable(@NonNull Network network) {} /** * Called when the network is about to be disconnected. Often paired with an @@ -3285,7 +3289,7 @@ public class ConnectivityManager { * network connected. Note that the network may suffer a * hard loss at any time. */ - public void onLosing(Network network, int maxMsToLive) {} + public void onLosing(@NonNull Network network, int maxMsToLive) {} /** * Called when the framework has a hard loss of the network or when the @@ -3293,7 +3297,7 @@ public class ConnectivityManager { * * @param network The {@link Network} lost. */ - public void onLost(Network network) {} + public void onLost(@NonNull Network network) {} /** * Called if no network is found in the timeout time specified in @@ -3313,8 +3317,8 @@ public class ConnectivityManager { * @param networkCapabilities The new {@link android.net.NetworkCapabilities} for this * network. */ - public void onCapabilitiesChanged(Network network, - NetworkCapabilities networkCapabilities) {} + public void onCapabilitiesChanged(@NonNull Network network, + @NonNull NetworkCapabilities networkCapabilities) {} /** * Called when the network the framework connected to for this request @@ -3323,7 +3327,8 @@ public class ConnectivityManager { * @param network The {@link Network} whose link properties have changed. * @param linkProperties The new {@link LinkProperties} for this network. */ - public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) {} + public void onLinkPropertiesChanged(@NonNull Network network, + @NonNull LinkProperties linkProperties) {} /** * Called when the network the framework connected to for this request @@ -3334,7 +3339,7 @@ public class ConnectivityManager { * a tunnel, etc. * @hide */ - public void onNetworkSuspended(Network network) {} + public void onNetworkSuspended(@NonNull Network network) {} /** * Called when the network the framework connected to for this request @@ -3342,7 +3347,7 @@ public class ConnectivityManager { * preceded by a matching {@link NetworkCallback#onNetworkSuspended} call. * @hide */ - public void onNetworkResumed(Network network) {} + public void onNetworkResumed(@NonNull Network network) {} /** * Called when access to the specified network is blocked or unblocked. diff --git a/core/java/android/net/DnsResolver.java b/core/java/android/net/DnsResolver.java index 59802514c7..06c32c675a 100644 --- a/core/java/android/net/DnsResolver.java +++ b/core/java/android/net/DnsResolver.java @@ -22,6 +22,10 @@ import static android.net.NetworkUtils.resNetworkResult; import static android.net.NetworkUtils.resNetworkSend; import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR; import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; +import static android.system.OsConstants.IPPROTO_UDP; +import static android.system.OsConstants.SOCK_DGRAM; import android.annotation.CallbackExecutor; import android.annotation.IntDef; @@ -30,12 +34,18 @@ import android.annotation.Nullable; import android.os.CancellationSignal; import android.os.Looper; import android.system.ErrnoException; +import android.system.Os; import android.util.Log; +import libcore.io.IoUtils; + import java.io.FileDescriptor; +import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; @@ -52,6 +62,7 @@ public final class DnsResolver { private static final String TAG = "DnsResolver"; private static final int FD_EVENTS = EVENT_INPUT | EVENT_ERROR; private static final int MAXPACKET = 8 * 1024; + private static final int SLEEP_TIME_MS = 2; @IntDef(prefix = { "CLASS_" }, value = { CLASS_IN @@ -188,9 +199,9 @@ public final class DnsResolver { * Send a raw DNS query. * The answer will be provided asynchronously through the provided {@link AnswerCallback}. * - * @param network {@link Network} specifying which network for querying. + * @param network {@link Network} specifying which network to query on. * {@code null} for query on default network. - * @param query blob message + * @param query blob message to query * @param flags flags as a combination of the FLAGS_* constants * @param executor The {@link Executor} that the callback should be executed on. * @param cancellationSignal used by the caller to signal if the query should be @@ -205,26 +216,32 @@ public final class DnsResolver { if (cancellationSignal != null && cancellationSignal.isCanceled()) { return; } + final Object lock = new Object(); final FileDescriptor queryfd; try { queryfd = resNetworkSend((network != null ? network.netId : NETID_UNSET), query, query.length, flags); } catch (ErrnoException e) { - callback.onQueryException(e); + executor.execute(() -> { + callback.onQueryException(e); + }); return; } - maybeAddCancellationSignal(cancellationSignal, queryfd); - registerFDListener(executor, queryfd, callback); + synchronized (lock) { + registerFDListener(executor, queryfd, callback, cancellationSignal, lock); + if (cancellationSignal == null) return; + addCancellationSignal(cancellationSignal, queryfd, lock); + } } /** * Send a DNS query with the specified name, class and query type. * The answer will be provided asynchronously through the provided {@link AnswerCallback}. * - * @param network {@link Network} specifying which network for querying. + * @param network {@link Network} specifying which network to query on. * {@code null} for query on default network. - * @param domain domain name for querying + * @param domain domain name to query * @param nsClass dns class as one of the CLASS_* constants * @param nsType dns resource record (RR) type as one of the TYPE_* constants * @param flags flags as a combination of the FLAGS_* constants @@ -242,40 +259,187 @@ public final class DnsResolver { if (cancellationSignal != null && cancellationSignal.isCanceled()) { return; } + final Object lock = new Object(); final FileDescriptor queryfd; try { queryfd = resNetworkQuery((network != null ? network.netId : NETID_UNSET), domain, nsClass, nsType, flags); } catch (ErrnoException e) { - callback.onQueryException(e); + executor.execute(() -> { + callback.onQueryException(e); + }); return; } + synchronized (lock) { + registerFDListener(executor, queryfd, callback, cancellationSignal, lock); + if (cancellationSignal == null) return; + addCancellationSignal(cancellationSignal, queryfd, lock); + } + } - maybeAddCancellationSignal(cancellationSignal, queryfd); - registerFDListener(executor, queryfd, callback); + private class InetAddressAnswerAccumulator extends InetAddressAnswerCallback { + private final List mAllAnswers; + private ParseException mParseException; + private ErrnoException mErrnoException; + private final InetAddressAnswerCallback mUserCallback; + private final int mTargetAnswerCount; + private int mReceivedAnswerCount = 0; + + InetAddressAnswerAccumulator(int size, @NonNull InetAddressAnswerCallback callback) { + mTargetAnswerCount = size; + mAllAnswers = new ArrayList<>(); + mUserCallback = callback; + } + + private boolean maybeReportException() { + if (mErrnoException != null) { + mUserCallback.onQueryException(mErrnoException); + return true; + } + if (mParseException != null) { + mUserCallback.onParseException(mParseException); + return true; + } + return false; + } + + private void maybeReportAnswer() { + if (++mReceivedAnswerCount != mTargetAnswerCount) return; + if (mAllAnswers.isEmpty() && maybeReportException()) return; + // TODO: Do RFC6724 sort. + mUserCallback.onAnswer(mAllAnswers); + } + + @Override + public void onAnswer(@NonNull List answer) { + mAllAnswers.addAll(answer); + maybeReportAnswer(); + } + + @Override + public void onParseException(@NonNull ParseException e) { + mParseException = e; + maybeReportAnswer(); + } + + @Override + public void onQueryException(@NonNull ErrnoException e) { + mErrnoException = e; + maybeReportAnswer(); + } + } + + /** + * Send a DNS query with the specified name, get back a set of InetAddresses asynchronously. + * The answer will be provided asynchronously through the provided + * {@link InetAddressAnswerCallback}. + * + * @param network {@link Network} specifying which network to query on. + * {@code null} for query on default network. + * @param domain domain name to query + * @param flags flags as a combination of the FLAGS_* constants + * @param executor The {@link Executor} that the callback should be executed on. + * @param cancellationSignal used by the caller to signal if the query should be + * cancelled. May be {@code null}. + * @param callback an {@link InetAddressAnswerCallback} which will be called to notify the + * caller of the result of dns query. + */ + public void query(@Nullable Network network, @NonNull String domain, @QueryFlag int flags, + @NonNull @CallbackExecutor Executor executor, + @Nullable CancellationSignal cancellationSignal, + @NonNull InetAddressAnswerCallback callback) { + if (cancellationSignal != null && cancellationSignal.isCanceled()) { + return; + } + final Object lock = new Object(); + final boolean queryIpv6 = haveIpv6(network); + final boolean queryIpv4 = haveIpv4(network); + + final FileDescriptor v4fd; + final FileDescriptor v6fd; + + int queryCount = 0; + + if (queryIpv6) { + try { + v6fd = resNetworkQuery((network != null + ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_AAAA, flags); + } catch (ErrnoException e) { + executor.execute(() -> { + callback.onQueryException(e); + }); + return; + } + queryCount++; + } else v6fd = null; + + // TODO: Use device flag to control the sleep time. + // Avoiding gateways drop packets if queries are sent too close together + try { + Thread.sleep(SLEEP_TIME_MS); + } catch (InterruptedException ex) { } + + if (queryIpv4) { + try { + v4fd = resNetworkQuery((network != null + ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_A, flags); + } catch (ErrnoException e) { + if (queryIpv6) resNetworkCancel(v6fd); // Closes fd, marks it invalid. + executor.execute(() -> { + callback.onQueryException(e); + }); + return; + } + queryCount++; + } else v4fd = null; + + final InetAddressAnswerAccumulator accumulator = + new InetAddressAnswerAccumulator(queryCount, callback); + + synchronized (lock) { + if (queryIpv6) { + registerFDListener(executor, v6fd, accumulator, cancellationSignal, lock); + } + if (queryIpv4) { + registerFDListener(executor, v4fd, accumulator, cancellationSignal, lock); + } + if (cancellationSignal == null) return; + cancellationSignal.setOnCancelListener(() -> { + synchronized (lock) { + if (queryIpv4) cancelQuery(v4fd); + if (queryIpv6) cancelQuery(v6fd); + } + }); + } } private void registerFDListener(@NonNull Executor executor, - @NonNull FileDescriptor queryfd, @NonNull AnswerCallback answerCallback) { + @NonNull FileDescriptor queryfd, @NonNull AnswerCallback answerCallback, + @Nullable CancellationSignal cancellationSignal, @NonNull Object lock) { Looper.getMainLooper().getQueue().addOnFileDescriptorEventListener( queryfd, FD_EVENTS, (fd, events) -> { executor.execute(() -> { - byte[] answerbuf = null; - try { - answerbuf = resNetworkResult(fd); - } catch (ErrnoException e) { - Log.e(TAG, "resNetworkResult:" + e.toString()); - answerCallback.onQueryException(e); - return; - } + synchronized (lock) { + if (cancellationSignal != null && cancellationSignal.isCanceled()) { + return; + } + byte[] answerbuf = null; + try { + answerbuf = resNetworkResult(fd); // Closes fd, marks it invalid. + } catch (ErrnoException e) { + Log.e(TAG, "resNetworkResult:" + e.toString()); + answerCallback.onQueryException(e); + return; + } - try { - answerCallback.onAnswer( - answerCallback.parser.parse(answerbuf)); - } catch (ParseException e) { - answerCallback.onParseException(e); + try { + answerCallback.onAnswer( + answerCallback.parser.parse(answerbuf)); + } catch (ParseException e) { + answerCallback.onParseException(e); + } } }); // Unregister this fd listener @@ -283,15 +447,51 @@ public final class DnsResolver { }); } - private void maybeAddCancellationSignal(@Nullable CancellationSignal cancellationSignal, - @NonNull FileDescriptor queryfd) { - if (cancellationSignal == null) return; - cancellationSignal.setOnCancelListener( - () -> { - Looper.getMainLooper().getQueue() - .removeOnFileDescriptorEventListener(queryfd); - resNetworkCancel(queryfd); - }); + private void cancelQuery(@NonNull FileDescriptor queryfd) { + if (!queryfd.valid()) return; + Looper.getMainLooper().getQueue().removeOnFileDescriptorEventListener(queryfd); + resNetworkCancel(queryfd); // Closes fd, marks it invalid. + } + + private void addCancellationSignal(@NonNull CancellationSignal cancellationSignal, + @NonNull FileDescriptor queryfd, @NonNull Object lock) { + cancellationSignal.setOnCancelListener(() -> { + synchronized (lock) { + cancelQuery(queryfd); + } + }); + } + + // These two functions match the behaviour of have_ipv4 and have_ipv6 in the native resolver. + private boolean haveIpv4(@Nullable Network network) { + final SocketAddress addrIpv4 = + new InetSocketAddress(InetAddresses.parseNumericAddress("8.8.8.8"), 0); + return checkConnectivity(network, AF_INET, addrIpv4); + } + + private boolean haveIpv6(@Nullable Network network) { + final SocketAddress addrIpv6 = + new InetSocketAddress(InetAddresses.parseNumericAddress("2000::"), 0); + return checkConnectivity(network, AF_INET6, addrIpv6); + } + + private boolean checkConnectivity(@Nullable Network network, + int domain, @NonNull SocketAddress addr) { + final FileDescriptor socket; + try { + socket = Os.socket(domain, SOCK_DGRAM, IPPROTO_UDP); + } catch (ErrnoException e) { + return false; + } + try { + if (network != null) network.bindSocket(socket); + Os.connect(socket, addr); + } catch (IOException | ErrnoException e) { + return false; + } finally { + IoUtils.closeQuietly(socket); + } + return true; } private static class DnsAddressAnswer extends DnsPacket { diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java index 402bffdc2a..8cfe6df678 100644 --- a/core/java/android/net/IpPrefix.java +++ b/core/java/android/net/IpPrefix.java @@ -16,6 +16,7 @@ package android.net; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.SystemApi; import android.annotation.TestApi; @@ -71,7 +72,7 @@ public final class IpPrefix implements Parcelable { * * @hide */ - public IpPrefix(@NonNull byte[] address, int prefixLength) { + public IpPrefix(@NonNull byte[] address, @IntRange(from = 0, to = 128) int prefixLength) { this.address = address.clone(); this.prefixLength = prefixLength; checkAndMaskAddressAndPrefixLength(); @@ -88,7 +89,7 @@ public final class IpPrefix implements Parcelable { */ @SystemApi @TestApi - public IpPrefix(@NonNull InetAddress address, int prefixLength) { + public IpPrefix(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength) { // We don't reuse the (byte[], int) constructor because it calls clone() on the byte array, // which is unnecessary because getAddress() already returns a clone. this.address = address.getAddress(); @@ -150,13 +151,13 @@ public final class IpPrefix implements Parcelable { * * @return the address in the form of a byte array. */ - public InetAddress getAddress() { + public @NonNull InetAddress getAddress() { try { return InetAddress.getByAddress(address); } catch (UnknownHostException e) { // Cannot happen. InetAddress.getByAddress can only throw an exception if the byte // array is the wrong length, but we check that in the constructor. - return null; + throw new IllegalArgumentException("Address is invalid"); } } @@ -166,7 +167,7 @@ public final class IpPrefix implements Parcelable { * * @return the address in the form of a byte array. */ - public byte[] getRawAddress() { + public @NonNull byte[] getRawAddress() { return address.clone(); } @@ -175,6 +176,7 @@ public final class IpPrefix implements Parcelable { * * @return the prefix length. */ + @IntRange(from = 0, to = 128) public int getPrefixLength() { return prefixLength; } @@ -183,10 +185,10 @@ public final class IpPrefix implements Parcelable { * Determines whether the prefix contains the specified address. * * @param address An {@link InetAddress} to test. - * @return {@code true} if the prefix covers the given address. + * @return {@code true} if the prefix covers the given address. {@code false} otherwise. */ - public boolean contains(InetAddress address) { - byte[] addrBytes = (address == null) ? null : address.getAddress(); + public boolean contains(@NonNull InetAddress address) { + byte[] addrBytes = address.getAddress(); if (addrBytes == null || addrBytes.length != this.address.length) { return false; } @@ -201,7 +203,7 @@ public final class IpPrefix implements Parcelable { * @param otherPrefix the prefix to test * @hide */ - public boolean containsPrefix(IpPrefix otherPrefix) { + public boolean containsPrefix(@NonNull IpPrefix otherPrefix) { if (otherPrefix.getPrefixLength() < prefixLength) return false; final byte[] otherAddress = otherPrefix.getRawAddress(); NetworkUtils.maskRawAddress(otherAddress, prefixLength); diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java index 333603f3a0..93dd2e4d77 100644 --- a/core/java/android/net/LinkAddress.java +++ b/core/java/android/net/LinkAddress.java @@ -25,6 +25,7 @@ import static android.system.OsConstants.RT_SCOPE_LINK; import static android.system.OsConstants.RT_SCOPE_SITE; import static android.system.OsConstants.RT_SCOPE_UNIVERSE; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; @@ -170,7 +171,7 @@ public class LinkAddress implements Parcelable { * Constructs a new {@code LinkAddress} from an {@code InetAddress} and prefix length, with * the specified flags and scope. Flags and scope are not checked for validity. * @param address The IP address. - * @param prefixLength The prefix length. + * @param prefixLength The prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6). * @param flags A bitmask of {@code IFA_F_*} values representing properties of the address. * @param scope An integer defining the scope in which the address is unique (e.g., * {@link OsConstants#RT_SCOPE_LINK} or {@link OsConstants#RT_SCOPE_SITE}). @@ -178,7 +179,8 @@ public class LinkAddress implements Parcelable { */ @SystemApi @TestApi - public LinkAddress(InetAddress address, int prefixLength, int flags, int scope) { + public LinkAddress(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength, + int flags, int scope) { init(address, prefixLength, flags, scope); } @@ -186,12 +188,13 @@ public class LinkAddress implements Parcelable { * Constructs a new {@code LinkAddress} from an {@code InetAddress} and a prefix length. * The flags are set to zero and the scope is determined from the address. * @param address The IP address. - * @param prefixLength The prefix length. + * @param prefixLength The prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6). * @hide */ @SystemApi @TestApi - public LinkAddress(@NonNull InetAddress address, int prefixLength) { + public LinkAddress(@NonNull InetAddress address, + @IntRange(from = 0, to = 128) int prefixLength) { this(address, prefixLength, 0, 0); this.scope = scopeForUnicastAddress(address); } @@ -202,7 +205,7 @@ public class LinkAddress implements Parcelable { * @param interfaceAddress The interface address. * @hide */ - public LinkAddress(InterfaceAddress interfaceAddress) { + public LinkAddress(@NonNull InterfaceAddress interfaceAddress) { this(interfaceAddress.getAddress(), interfaceAddress.getNetworkPrefixLength()); } @@ -306,6 +309,7 @@ public class LinkAddress implements Parcelable { /** * Returns the prefix length of this {@code LinkAddress}. */ + @IntRange(from = 0, to = 128) public int getPrefixLength() { return prefixLength; } @@ -316,6 +320,7 @@ public class LinkAddress implements Parcelable { * @hide */ @UnsupportedAppUsage + @IntRange(from = 0, to = 128) public int getNetworkPrefixLength() { return getPrefixLength(); } diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index d5ca6642a3..d3f48acdd4 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -316,9 +316,6 @@ public final class LinkProperties implements Parcelable { @SystemApi @TestApi public boolean removeLinkAddress(@NonNull LinkAddress toRemove) { - if (toRemove == null) { - return false; - } int i = findLinkAddressIndex(toRemove); if (i >= 0) { mLinkAddresses.remove(i); @@ -391,10 +388,7 @@ public final class LinkProperties implements Parcelable { @TestApi @SystemApi public boolean removeDnsServer(@NonNull InetAddress dnsServer) { - if (dnsServer != null) { - return mDnses.remove(dnsServer); - } - return false; + return mDnses.remove(dnsServer); } /** diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java index 51cbed48e0..4270740cc7 100644 --- a/core/java/android/net/NetworkRequest.java +++ b/core/java/android/net/NetworkRequest.java @@ -17,6 +17,7 @@ package android.net; import android.annotation.NonNull; +import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; import android.net.NetworkCapabilities.NetCapability; @@ -343,10 +344,14 @@ public class NetworkRequest implements Parcelable { * current value. A value of {@code SIGNAL_STRENGTH_UNSPECIFIED} means no value when * received and has no effect when requesting a callback. * + *

This method requires the caller to hold the + * {@link android.Manifest.permission#NETWORK_SIGNAL_STRENGTH_WAKEUP} permission + * * @param signalStrength the bearer-specific signal strength. * @hide */ @SystemApi + @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public @NonNull Builder setSignalStrength(int signalStrength) { mNetworkCapabilities.setSignalStrength(signalStrength); return this; diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java index b0239c8393..52d3fc48a3 100644 --- a/core/java/android/net/RouteInfo.java +++ b/core/java/android/net/RouteInfo.java @@ -16,6 +16,8 @@ package android.net; +import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; @@ -24,6 +26,8 @@ import android.os.Build; import android.os.Parcel; import android.os.Parcelable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; @@ -51,20 +55,32 @@ import java.util.Objects; * (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; @@ -108,13 +124,14 @@ public final class RouteInfo implements Parcelable { * @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 @TestApi public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway, - @Nullable String iface, int type) { + @Nullable String iface, @RouteType int type) { switch (type) { case RTN_UNICAST: case RTN_UNREACHABLE: @@ -173,10 +190,24 @@ public final class RouteInfo implements Parcelable { } /** - * @hide + * Constructs a {@code RouteInfo} object. + * + * If destination is null, then gateway must be specified and the + * constructed route is either the IPv4 default route 0.0.0.0 + * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default + * route ::/0 if gateway is an instance of {@link Inet6Address}. + *

+ * 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 - public RouteInfo(IpPrefix destination, InetAddress gateway, String iface) { + public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway, + @Nullable String iface) { this(destination, gateway, iface, RTN_UNICAST); } @@ -184,7 +215,8 @@ public final class RouteInfo implements Parcelable { * @hide */ @UnsupportedAppUsage - public RouteInfo(LinkAddress destination, InetAddress gateway, String iface) { + public RouteInfo(@Nullable LinkAddress destination, @Nullable InetAddress gateway, + @Nullable String iface) { this(destination == null ? null : new IpPrefix(destination.getAddress(), destination.getPrefixLength()), gateway, iface); @@ -205,7 +237,7 @@ public final class RouteInfo implements Parcelable { * * @hide */ - public RouteInfo(IpPrefix destination, InetAddress gateway) { + public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway) { this(destination, gateway, null); } @@ -215,7 +247,7 @@ public final class RouteInfo implements Parcelable { * TODO: Remove this. */ @UnsupportedAppUsage - public RouteInfo(LinkAddress destination, InetAddress gateway) { + public RouteInfo(@Nullable LinkAddress destination, @Nullable InetAddress gateway) { this(destination, gateway, null); } @@ -227,7 +259,7 @@ public final class RouteInfo implements Parcelable { * @hide */ @UnsupportedAppUsage - public RouteInfo(InetAddress gateway) { + public RouteInfo(@NonNull InetAddress gateway) { this((IpPrefix) null, gateway, null); } @@ -239,35 +271,36 @@ public final class RouteInfo implements Parcelable { * * @hide */ - public RouteInfo(IpPrefix destination) { + public RouteInfo(@NonNull IpPrefix destination) { this(destination, null, null); } /** * @hide */ - public RouteInfo(LinkAddress destination) { + public RouteInfo(@NonNull LinkAddress destination) { this(destination, null, null); } /** * @hide */ - public RouteInfo(IpPrefix destination, int type) { + public RouteInfo(@NonNull IpPrefix destination, @RouteType int type) { this(destination, null, null, type); } /** * @hide */ - public static RouteInfo makeHostRoute(InetAddress host, String iface) { + public static RouteInfo makeHostRoute(@NonNull InetAddress host, @Nullable String iface) { return makeHostRoute(host, null, iface); } /** * @hide */ - public static RouteInfo makeHostRoute(InetAddress host, InetAddress gateway, String iface) { + public static RouteInfo makeHostRoute(@Nullable InetAddress host, @Nullable InetAddress gateway, + @Nullable String iface) { if (host == null) return null; if (host instanceof Inet4Address) { @@ -290,6 +323,7 @@ public final class RouteInfo implements Parcelable { * * @return {@link IpPrefix} specifying the destination. This is never {@code null}. */ + @NonNull public IpPrefix getDestination() { return mDestination; } @@ -298,6 +332,7 @@ public final class RouteInfo implements Parcelable { * TODO: Convert callers to use IpPrefix and then remove. * @hide */ + @NonNull public LinkAddress getDestinationLinkAddress() { return new LinkAddress(mDestination.getAddress(), mDestination.getPrefixLength()); } @@ -308,6 +343,7 @@ public final class RouteInfo implements Parcelable { * @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; } @@ -317,6 +353,7 @@ public final class RouteInfo implements Parcelable { * * @return The name of the interface used for this route. */ + @Nullable public String getInterface() { return mInterface; } @@ -330,6 +367,7 @@ public final class RouteInfo implements Parcelable { */ @TestApi @SystemApi + @RouteType public int getType() { return mType; } @@ -401,6 +439,7 @@ public final class RouteInfo implements Parcelable { * @hide */ @UnsupportedAppUsage + @Nullable public static RouteInfo selectBestRoute(Collection routes, InetAddress dest) { if ((routes == null) || (dest == null)) return null; diff --git a/core/java/android/net/apf/ApfCapabilities.java b/core/java/android/net/apf/ApfCapabilities.java index 17a03c7c89..4dd2ace59c 100644 --- a/core/java/android/net/apf/ApfCapabilities.java +++ b/core/java/android/net/apf/ApfCapabilities.java @@ -19,14 +19,17 @@ package android.net.apf; import android.annotation.NonNull; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.content.Context; +import android.content.res.Resources; import android.os.Parcel; import android.os.Parcelable; import com.android.internal.R; /** - * APF program support capabilities. + * APF program support capabilities. APF stands for Android Packet Filtering and it is a flexible + * way to drop unwanted network packets to save power. + * + * See documentation at hardware/google/apf/apf.h * * This class is immutable. * @hide @@ -104,10 +107,11 @@ public final class ApfCapabilities implements Parcelable { } /** - * Returns true if the APF interpreter advertises support for the data buffer access opcodes - * LDDW and STDW. + * Determines whether the APF interpreter advertises support for the data buffer access opcodes + * LDDW (LoaD Data Word) and STDW (STore Data Word). Full LDDW (LoaD Data Word) and + * STDW (STore Data Word) support is present from APFv4 on. * - * Full LDDW and STDW support is present from APFv4 on. + * @return {@code true} if the IWifiStaIface#readApfPacketFilterData is supported. */ public boolean hasDataAccess() { return apfVersionSupported >= 4; @@ -116,14 +120,14 @@ public final class ApfCapabilities implements Parcelable { /** * @return Whether the APF Filter in the device should filter out IEEE 802.3 Frames. */ - public static boolean getApfDrop8023Frames(@NonNull Context context) { - return context.getResources().getBoolean(R.bool.config_apfDrop802_3Frames); + public static boolean getApfDrop8023Frames() { + return Resources.getSystem().getBoolean(R.bool.config_apfDrop802_3Frames); } /** * @return An array of blacklisted EtherType, packets with EtherTypes within it will be dropped. */ - public static @NonNull int[] getApfEthTypeBlackList(@NonNull Context context) { - return context.getResources().getIntArray(R.array.config_apfEthTypeBlackList); + public static @NonNull int[] getApfEtherTypeBlackList() { + return Resources.getSystem().getIntArray(R.array.config_apfEthTypeBlackList); } } diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index d7a981ed3e..82acf6fb43 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -470,6 +470,7 @@ static jbyteArray android_net_utils_resNetworkResult(JNIEnv *env, jobject thiz, std::vector buf(MAXPACKETSIZE, 0); int res = resNetworkResult(fd, &rcode, buf.data(), MAXPACKETSIZE); + jniSetFileDescriptorOfFD(env, javaFd, -1); if (res < 0) { throwErrnoException(env, "resNetworkResult", -res); return nullptr; @@ -490,6 +491,7 @@ static jbyteArray android_net_utils_resNetworkResult(JNIEnv *env, jobject thiz, static void android_net_utils_resNetworkCancel(JNIEnv *env, jobject thiz, jobject javaFd) { int fd = jniGetFDFromFileDescriptor(env, javaFd); resNetworkCancel(fd); + jniSetFileDescriptorOfFD(env, javaFd, -1); } static jobject android_net_utils_getTcpRepairWindow(JNIEnv *env, jobject thiz, jobject javaFd) { diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 2be92cde68..8ad23b0e30 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -63,6 +63,7 @@ import android.net.ConnectionInfo; import android.net.ConnectivityManager; import android.net.ICaptivePortal; import android.net.IConnectivityManager; +import android.net.IDnsResolver; import android.net.IIpConnectivityMetrics; import android.net.INetd; import android.net.INetdEventCallback; @@ -294,6 +295,8 @@ public class ConnectivityService extends IConnectivityManager.Stub private INetworkManagementService mNMS; @VisibleForTesting + protected IDnsResolver mDnsResolver; + @VisibleForTesting protected INetd mNetd; private INetworkStatsService mStatsService; private INetworkPolicyManager mPolicyManager; @@ -525,6 +528,11 @@ public class ConnectivityService extends IConnectivityManager.Stub return sMagicDecoderRing.get(what, Integer.toString(what)); } + private static IDnsResolver getDnsResolver() { + return IDnsResolver.Stub + .asInterface(ServiceManager.getService("dnsresolver")); + } + /** Handler thread used for both of the handlers below. */ @VisibleForTesting protected final HandlerThread mHandlerThread; @@ -810,13 +818,14 @@ public class ConnectivityService extends IConnectivityManager.Stub public ConnectivityService(Context context, INetworkManagementService netManager, INetworkStatsService statsService, INetworkPolicyManager policyManager) { - this(context, netManager, statsService, policyManager, new IpConnectivityLog()); + this(context, netManager, statsService, policyManager, + getDnsResolver(), new IpConnectivityLog()); } @VisibleForTesting protected ConnectivityService(Context context, INetworkManagementService netManager, INetworkStatsService statsService, INetworkPolicyManager policyManager, - IpConnectivityLog logger) { + IDnsResolver dnsresolver, IpConnectivityLog logger) { if (DBG) log("ConnectivityService starting up"); mSystemProperties = getSystemProperties(); @@ -853,6 +862,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mPolicyManagerInternal = checkNotNull( LocalServices.getService(NetworkPolicyManagerInternal.class), "missing NetworkPolicyManagerInternal"); + mDnsResolver = checkNotNull(dnsresolver, "missing IDnsResolver"); mProxyTracker = makeProxyTracker(); mNetd = NetdService.getInstance(); @@ -1006,7 +1016,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mMultipathPolicyTracker = new MultipathPolicyTracker(mContext, mHandler); - mDnsManager = new DnsManager(mContext, mNMS, mSystemProperties); + mDnsManager = new DnsManager(mContext, mDnsResolver, mSystemProperties); registerPrivateDnsSettingsCallbacks(); } @@ -1882,6 +1892,15 @@ public class ConnectivityService extends IConnectivityManager.Stub return false; } + private boolean checkAnyPermissionOf(int pid, int uid, String... permissions) { + for (String permission : permissions) { + if (mContext.checkPermission(permission, pid, uid) == PERMISSION_GRANTED) { + return true; + } + } + return false; + } + private void enforceAnyPermissionOf(String... permissions) { if (!checkAnyPermissionOf(permissions)) { throw new SecurityException("Requires one of the following permissions: " @@ -1956,6 +1975,12 @@ public class ConnectivityService extends IConnectivityManager.Stub NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK); } + private boolean checkNetworkSignalStrengthWakeupPermission(int pid, int uid) { + return checkAnyPermissionOf(pid, uid, + android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP, + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK); + } + private void enforceConnectivityRestrictedNetworksPermission() { try { mContext.enforceCallingOrSelfPermission( @@ -3021,9 +3046,9 @@ public class ConnectivityService extends IConnectivityManager.Stub // NetworkFactories, so network traffic isn't interrupted for an unnecessarily // long time. try { - mNMS.removeNetwork(nai.network.netId); - } catch (Exception e) { - loge("Exception removing network: " + e); + mNetd.networkDestroy(nai.network.netId); + } catch (RemoteException | ServiceSpecificException e) { + loge("Exception destroying network: " + e); } mDnsManager.removeNetwork(nai.network); } @@ -3728,16 +3753,6 @@ public class ConnectivityService extends IConnectivityManager.Stub break; } case EVENT_SYSTEM_READY: { - for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { - // Might have been called already in handleRegisterNetworkAgent since - // mSystemReady is set before sending EVENT_SYSTEM_READY, but calling - // this several times is fine. - try { - nai.networkMonitor().notifySystemReady(); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - } mMultipathPolicyTracker.start(); break; } @@ -4952,13 +4967,19 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - // This checks that the passed capabilities either do not request a specific SSID, or the - // calling app has permission to do so. + // This checks that the passed capabilities either do not request a specific SSID/SignalStrength + // , or the calling app has permission to do so. private void ensureSufficientPermissionsForRequest(NetworkCapabilities nc, int callerPid, int callerUid) { if (null != nc.getSSID() && !checkSettingsPermission(callerPid, callerUid)) { throw new SecurityException("Insufficient permissions to request a specific SSID"); } + + if (nc.hasSignalStrength() + && !checkNetworkSignalStrengthWakeupPermission(callerPid, callerUid)) { + throw new SecurityException( + "Insufficient permissions to request a specific signal strength"); + } } private ArrayList getSignalStrengthThresholds(NetworkAgentInfo nai) { @@ -5372,10 +5393,10 @@ public class ConnectivityService extends IConnectivityManager.Stub final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities); final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(), new Network(reserveNetId()), new NetworkInfo(networkInfo), lp, nc, currentScore, - mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd, mNMS, - factorySerialNumber); + mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd, mDnsResolver, + mNMS, factorySerialNumber); // Make sure the network capabilities reflect what the agent info says. - nai.networkCapabilities = mixInCapabilities(nai, nc); + nai.setNetworkCapabilities(mixInCapabilities(nai, nc)); final String extraInfo = networkInfo.getExtraInfo(); final String name = TextUtils.isEmpty(extraInfo) ? nai.networkCapabilities.getSSID() : extraInfo; @@ -5406,15 +5427,6 @@ public class ConnectivityService extends IConnectivityManager.Stub synchronized (mNetworkForNetId) { mNetworkForNetId.put(nai.network.netId, nai); } - synchronized (this) { - if (mSystemReady) { - try { - networkMonitor.notifySystemReady(); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - } - } try { networkMonitor.start(); @@ -5468,12 +5480,12 @@ public class ConnectivityService extends IConnectivityManager.Stub // Start or stop DNS64 detection and 464xlat according to network state. networkAgent.clatd.update(); notifyIfacesChangedForNetworkStats(); + try { + networkAgent.networkMonitor().notifyLinkPropertiesChanged(newLp); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } if (networkAgent.everConnected) { - try { - networkAgent.networkMonitor().notifyLinkPropertiesChanged(); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED); } } @@ -5701,7 +5713,7 @@ public class ConnectivityService extends IConnectivityManager.Stub final NetworkCapabilities prevNc; synchronized (nai) { prevNc = nai.networkCapabilities; - nai.networkCapabilities = newNc; + nai.setNetworkCapabilities(newNc); } updateUids(nai, prevNc, newNc); @@ -5716,11 +5728,6 @@ public class ConnectivityService extends IConnectivityManager.Stub // If the requestable capabilities have changed or the score changed, we can't have been // called by rematchNetworkAndRequests, so it's safe to start a rematch. rematchAllNetworksAndRequests(nai, oldScore); - try { - nai.networkMonitor().notifyNetworkCapabilitiesChanged(); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED); } @@ -5979,11 +5986,6 @@ public class ConnectivityService extends IConnectivityManager.Stub } if (capabilitiesChanged) { - try { - nai.networkMonitor().notifyNetworkCapabilitiesChanged(); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED); } @@ -6392,7 +6394,8 @@ public class ConnectivityService extends IConnectivityManager.Stub if (networkAgent.networkMisc.acceptPartialConnectivity) { networkAgent.networkMonitor().setAcceptPartialConnectivity(); } - networkAgent.networkMonitor().notifyNetworkConnected(); + networkAgent.networkMonitor().notifyNetworkConnected( + networkAgent.linkProperties, networkAgent.networkCapabilities); } catch (RemoteException e) { e.rethrowFromSystemServer(); } diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java index d8bb635f2c..1913635f80 100644 --- a/services/core/java/com/android/server/connectivity/DnsManager.java +++ b/services/core/java/com/android/server/connectivity/DnsManager.java @@ -30,13 +30,15 @@ import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; +import android.net.IDnsResolver; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkUtils; import android.net.Uri; import android.net.shared.PrivateDnsConfig; import android.os.Binder; -import android.os.INetworkManagementService; +import android.os.RemoteException; +import android.os.ServiceSpecificException; import android.os.UserHandle; import android.provider.Settings; import android.text.TextUtils; @@ -229,7 +231,7 @@ public class DnsManager { private final Context mContext; private final ContentResolver mContentResolver; - private final INetworkManagementService mNMS; + private final IDnsResolver mDnsResolver; private final MockableSystemProperties mSystemProperties; // TODO: Replace these Maps with SparseArrays. private final Map mPrivateDnsMap; @@ -243,10 +245,10 @@ public class DnsManager { private String mPrivateDnsMode; private String mPrivateDnsSpecifier; - public DnsManager(Context ctx, INetworkManagementService nms, MockableSystemProperties sp) { + public DnsManager(Context ctx, IDnsResolver dnsResolver, MockableSystemProperties sp) { mContext = ctx; mContentResolver = mContext.getContentResolver(); - mNMS = nms; + mDnsResolver = dnsResolver; mSystemProperties = sp; mPrivateDnsMap = new HashMap<>(); mPrivateDnsValidationMap = new HashMap<>(); @@ -260,6 +262,12 @@ public class DnsManager { } public void removeNetwork(Network network) { + try { + mDnsResolver.clearResolverConfiguration(network.netId); + } catch (RemoteException | ServiceSpecificException e) { + Slog.e(TAG, "Error clearing DNS configuration: " + e); + return; + } mPrivateDnsMap.remove(network.netId); mPrivateDnsValidationMap.remove(network.netId); } @@ -344,10 +352,12 @@ public class DnsManager { Slog.d(TAG, String.format("setDnsConfigurationForNetwork(%d, %s, %s, %s, %s, %s)", netId, Arrays.toString(assignedServers), Arrays.toString(domainStrs), Arrays.toString(params), tlsHostname, Arrays.toString(tlsServers))); + final String[] tlsFingerprints = new String[0]; try { - mNMS.setDnsConfigurationForNetwork( - netId, assignedServers, domainStrs, params, tlsHostname, tlsServers); - } catch (Exception e) { + mDnsResolver.setResolverConfiguration( + netId, assignedServers, domainStrs, params, + tlsHostname, tlsServers, tlsFingerprints); + } catch (RemoteException | ServiceSpecificException e) { Slog.e(TAG, "Error setting DNS configuration: " + e); return; } diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java index ce887eb4f0..35f7ea3ae0 100644 --- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java +++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java @@ -132,6 +132,7 @@ public class KeepaliveTracker { private static final int NOT_STARTED = 1; private static final int STARTING = 2; private static final int STARTED = 3; + private static final int STOPPING = 4; private int mStartedState = NOT_STARTED; KeepaliveInfo(@NonNull ISocketKeepaliveCallback callback, @@ -154,12 +155,19 @@ public class KeepaliveTracker { // keepalives are sent cannot be reused by another app even if the fd gets closed by // the user. A null is acceptable here for backward compatibility of PacketKeepalive // API. - // TODO: don't accept null fd after legacy packetKeepalive API is removed. try { if (fd != null) { mFd = Os.dup(fd); } else { - Log.d(TAG, "uid/pid " + mUid + "/" + mPid + " calls with null fd"); + Log.d(TAG, toString() + " calls with null fd"); + if (!mPrivileged) { + throw new SecurityException( + "null fd is not allowed for unprivileged access."); + } + if (mType == TYPE_TCP) { + throw new IllegalArgumentException( + "null fd is not allowed for tcp socket keepalives."); + } mFd = null; } } catch (ErrnoException e) { @@ -307,6 +315,7 @@ public class KeepaliveTracker { } } if (NOT_STARTED != mStartedState) { + mStartedState = STOPPING; Log.d(TAG, "Stopping keepalive " + mSlot + " on " + mNai.name()); if (mType == TYPE_NATT) { mNai.asyncChannel.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, mSlot); @@ -449,8 +458,8 @@ public class KeepaliveTracker { ki = mKeepalives.get(nai).get(slot); } catch(NullPointerException e) {} if (ki == null) { - Log.e(TAG, "Event " + message.what + " for unknown keepalive " + slot + " on " - + nai.name()); + Log.e(TAG, "Event " + message.what + "," + slot + "," + reason + + " for unknown keepalive " + slot + " on " + nai.name()); return; } @@ -469,27 +478,30 @@ public class KeepaliveTracker { // messages in order. // TODO : clarify this code and get rid of mStartedState. Using a StateMachine is an // option. - if (reason == SUCCESS && KeepaliveInfo.STARTING == ki.mStartedState) { - // Keepalive successfully started. - if (DBG) Log.d(TAG, "Started keepalive " + slot + " on " + nai.name()); - ki.mStartedState = KeepaliveInfo.STARTED; - try { - ki.mCallback.onStarted(slot); - } catch (RemoteException e) { - Log.w(TAG, "Discarded onStarted(" + slot + ") callback"); - } - } else { - // Keepalive successfully stopped, or error. - ki.mStartedState = KeepaliveInfo.NOT_STARTED; - if (reason == SUCCESS) { - // The message indicated success stopping : don't call handleStopKeepalive. - if (DBG) Log.d(TAG, "Successfully stopped keepalive " + slot + " on " + nai.name()); + if (KeepaliveInfo.STARTING == ki.mStartedState) { + if (SUCCESS == reason) { + // Keepalive successfully started. + if (DBG) Log.d(TAG, "Started keepalive " + slot + " on " + nai.name()); + ki.mStartedState = KeepaliveInfo.STARTED; + try { + ki.mCallback.onStarted(slot); + } catch (RemoteException e) { + Log.w(TAG, "Discarded onStarted(" + slot + ") callback"); + } } else { - // The message indicated some error trying to start or during the course of - // keepalive : do call handleStopKeepalive. + Log.d(TAG, "Failed to start keepalive " + slot + " on " + nai.name() + + ": " + reason); + // The message indicated some error trying to start: do call handleStopKeepalive. handleStopKeepalive(nai, slot, reason); - if (DBG) Log.d(TAG, "Keepalive " + slot + " on " + nai.name() + " error " + reason); } + } else if (KeepaliveInfo.STOPPING == ki.mStartedState) { + // The message indicated result of stopping : don't call handleStopKeepalive. + Log.d(TAG, "Stopped keepalive " + slot + " on " + nai.name() + + " stopped: " + reason); + ki.mStartedState = KeepaliveInfo.NOT_STARTED; + } else { + Log.wtf(TAG, "Event " + message.what + "," + slot + "," + reason + + " for keepalive in wrong state: " + ki.toString()); } } @@ -531,7 +543,8 @@ public class KeepaliveTracker { try { ki = new KeepaliveInfo(cb, nai, packet, intervalSeconds, KeepaliveInfo.TYPE_NATT, fd); - } catch (InvalidSocketException e) { + } catch (InvalidSocketException | IllegalArgumentException | SecurityException e) { + Log.e(TAG, "Fail to construct keepalive", e); notifyErrorCallback(cb, ERROR_INVALID_SOCKET); return; } @@ -570,7 +583,8 @@ public class KeepaliveTracker { try { ki = new KeepaliveInfo(cb, nai, packet, intervalSeconds, KeepaliveInfo.TYPE_TCP, fd); - } catch (InvalidSocketException e) { + } catch (InvalidSocketException | IllegalArgumentException | SecurityException e) { + Log.e(TAG, "Fail to construct keepalive e=" + e); notifyErrorCallback(cb, ERROR_INVALID_SOCKET); return; } diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java index 262ba7a475..66bd27c1a7 100644 --- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java +++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java @@ -17,6 +17,7 @@ package com.android.server.connectivity; import android.net.ConnectivityManager; +import android.net.IDnsResolver; import android.net.INetd; import android.net.InetAddresses; import android.net.InterfaceConfiguration; @@ -65,6 +66,7 @@ public class Nat464Xlat extends BaseNetworkObserver { NetworkInfo.State.SUSPENDED, }; + private final IDnsResolver mDnsResolver; private final INetd mNetd; private final INetworkManagementService mNMService; @@ -84,7 +86,9 @@ public class Nat464Xlat extends BaseNetworkObserver { private Inet6Address mIPv6Address; private State mState = State.IDLE; - public Nat464Xlat(NetworkAgentInfo nai, INetd netd, INetworkManagementService nmService) { + public Nat464Xlat(NetworkAgentInfo nai, INetd netd, IDnsResolver dnsResolver, + INetworkManagementService nmService) { + mDnsResolver = dnsResolver; mNetd = netd; mNMService = nmService; mNetwork = nai; @@ -269,7 +273,7 @@ public class Nat464Xlat extends BaseNetworkObserver { private void startPrefixDiscovery() { try { - mNetd.resolverStartPrefix64Discovery(getNetId()); + mDnsResolver.startPrefix64Discovery(getNetId()); mState = State.DISCOVERING; } catch (RemoteException | ServiceSpecificException e) { Slog.e(TAG, "Error starting prefix discovery on netId " + getNetId() + ": " + e); @@ -278,7 +282,7 @@ public class Nat464Xlat extends BaseNetworkObserver { private void stopPrefixDiscovery() { try { - mNetd.resolverStopPrefix64Discovery(getNetId()); + mDnsResolver.stopPrefix64Discovery(getNetId()); } catch (RemoteException | ServiceSpecificException e) { Slog.e(TAG, "Error stopping prefix discovery on netId " + getNetId() + ": " + e); } diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index 8f2825ca72..cfa91314f4 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -17,6 +17,7 @@ package com.android.server.connectivity; import android.content.Context; +import android.net.IDnsResolver; import android.net.INetd; import android.net.INetworkMonitor; import android.net.LinkProperties; @@ -29,6 +30,7 @@ import android.net.NetworkState; import android.os.Handler; import android.os.INetworkManagementService; import android.os.Messenger; +import android.os.RemoteException; import android.os.SystemClock; import android.util.Log; import android.util.SparseArray; @@ -120,7 +122,8 @@ public class NetworkAgentInfo implements Comparable { // This Network object is always valid. public final Network network; public LinkProperties linkProperties; - // This should only be modified via ConnectivityService.updateCapabilities(). + // This should only be modified by ConnectivityService, via setNetworkCapabilities(). + // TODO: make this private with a getter. public NetworkCapabilities networkCapabilities; public final NetworkMisc networkMisc; // Indicates if netd has been told to create this Network. From this point on the appropriate @@ -255,7 +258,7 @@ public class NetworkAgentInfo implements Comparable { public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info, LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler, NetworkMisc misc, ConnectivityService connService, INetd netd, - INetworkManagementService nms, int factorySerialNumber) { + IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber) { this.messenger = messenger; asyncChannel = ac; network = net; @@ -263,7 +266,7 @@ public class NetworkAgentInfo implements Comparable { linkProperties = lp; networkCapabilities = nc; currentScore = score; - clatd = new Nat464Xlat(this, netd, nms); + clatd = new Nat464Xlat(this, netd, dnsResolver, nms); mConnService = connService; mContext = context; mHandler = handler; @@ -278,6 +281,25 @@ public class NetworkAgentInfo implements Comparable { mNetworkMonitor = networkMonitor; } + /** + * Set the NetworkCapabilities on this NetworkAgentInfo. Also attempts to notify NetworkMonitor + * of the new capabilities, if NetworkMonitor has been created. + * + *

If {@link NetworkMonitor#notifyNetworkCapabilitiesChanged(NetworkCapabilities)} fails, + * the exception is logged but not reported to callers. + */ + public void setNetworkCapabilities(NetworkCapabilities nc) { + networkCapabilities = nc; + final INetworkMonitor nm = mNetworkMonitor; + if (nm != null) { + try { + nm.notifyNetworkCapabilitiesChanged(nc); + } catch (RemoteException e) { + Log.e(TAG, "Error notifying NetworkMonitor of updated NetworkCapabilities", e); + } + } + } + public ConnectivityService connService() { return mConnService; } diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java index 828a1e5886..ac3d6def6f 100644 --- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java +++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java @@ -19,6 +19,7 @@ package com.android.server.connectivity; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.telephony.SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; import android.app.Notification; import android.app.NotificationManager; @@ -26,9 +27,12 @@ import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.res.Resources; +import android.net.NetworkSpecifier; +import android.net.StringNetworkSpecifier; import android.net.wifi.WifiInfo; import android.os.UserHandle; import android.telephony.AccessNetworkConstants.TransportType; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Slog; @@ -195,7 +199,20 @@ public class NetworkNotificationManager { title = r.getString(R.string.network_available_sign_in, 0); // TODO: Change this to pull from NetworkInfo once a printable // name has been added to it - details = mTelephonyManager.getNetworkOperatorName(); + NetworkSpecifier specifier = nai.networkCapabilities.getNetworkSpecifier(); + int subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; + if (specifier instanceof StringNetworkSpecifier) { + try { + subId = Integer.parseInt( + ((StringNetworkSpecifier) specifier).specifier); + } catch (NumberFormatException e) { + Slog.e(TAG, "NumberFormatException on " + + ((StringNetworkSpecifier) specifier).specifier); + } + } + + details = mTelephonyManager.createForSubscriptionId(subId) + .getNetworkOperatorName(); break; default: title = r.getString(R.string.network_available_sign_in, 0); diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java index 123564eb4f..0c559346bc 100644 --- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java +++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java @@ -22,6 +22,7 @@ import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS; import static android.Manifest.permission.INTERNET; import static android.Manifest.permission.NETWORK_STACK; import static android.Manifest.permission.UPDATE_DEVICE_STATS; +import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED; import static android.content.pm.PackageManager.GET_PERMISSIONS; import static android.content.pm.PackageManager.MATCH_ANY_USER; import static android.os.Process.INVALID_UID; @@ -42,13 +43,15 @@ import android.os.INetworkManagementService; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; +import android.util.ArraySet; import android.util.Log; -import android.util.Slog; +import android.util.SparseArray; import android.util.SparseIntArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.server.LocalServices; +import com.android.server.SystemConfig; import java.util.ArrayList; import java.util.HashMap; @@ -83,41 +86,32 @@ public class PermissionMonitor { private final Map mApps = new HashMap<>(); private class PackageListObserver implements PackageManagerInternal.PackageListObserver { - @Override - public void onPackageAdded(String packageName, int uid) { - final PackageInfo app = getPackageInfo(packageName); - if (app == null) { - Slog.wtf(TAG, "Failed to get information of installed package: " + packageName); - return; - } - if (uid == INVALID_UID) { - Slog.wtf(TAG, "Failed to get the uid of installed package: " + packageName - + "uid: " + uid); - return; - } - if (app.requestedPermissions == null) { - return; - } - sendPackagePermissionsForUid(uid, - getNetdPermissionMask(app.requestedPermissions)); - } - @Override - public void onPackageRemoved(String packageName, int uid) { + private int getPermissionForUid(int uid) { int permission = 0; - // If there are still packages remain under the same uid, check the permission of the - // remaining packages. We only remove the permission for a given uid when all packages - // for that uid no longer have that permission. + // Check all the packages for this UID. The UID has the permission if any of the + // packages in it has the permission. String[] packages = mPackageManager.getPackagesForUid(uid); if (packages != null && packages.length > 0) { for (String name : packages) { final PackageInfo app = getPackageInfo(name); if (app != null && app.requestedPermissions != null) { - permission |= getNetdPermissionMask(app.requestedPermissions); + permission |= getNetdPermissionMask(app.requestedPermissions, + app.requestedPermissionsFlags); } } } - sendPackagePermissionsForUid(uid, permission); + return permission; + } + + @Override + public void onPackageAdded(String packageName, int uid) { + sendPackagePermissionsForUid(uid, getPermissionForUid(uid)); + } + + @Override + public void onPackageRemoved(String packageName, int uid) { + sendPackagePermissionsForUid(uid, getPermissionForUid(uid)); } } @@ -167,12 +161,9 @@ public class PermissionMonitor { } //TODO: unify the management of the permissions into one codepath. - if (app.requestedPermissions != null) { - int otherNetdPerms = getNetdPermissionMask(app.requestedPermissions); - if (otherNetdPerms != 0) { - netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms); - } - } + int otherNetdPerms = getNetdPermissionMask(app.requestedPermissions, + app.requestedPermissionsFlags); + netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms); } List users = mUserManager.getUsers(true); // exclude dying users @@ -182,6 +173,23 @@ public class PermissionMonitor { } } + final SparseArray> systemPermission = + SystemConfig.getInstance().getSystemPermissions(); + for (int i = 0; i < systemPermission.size(); i++) { + ArraySet perms = systemPermission.valueAt(i); + int uid = systemPermission.keyAt(i); + int netdPermission = 0; + // Get the uids of native services that have UPDATE_DEVICE_STATS permission. + if (perms != null) { + netdPermission |= perms.contains(UPDATE_DEVICE_STATS) + ? INetd.PERMISSION_UPDATE_DEVICE_STATS : 0; + } + // For internet permission, the native services have their own selinux domains and + // sepolicy will control the socket creation during run time. netd cannot block the + // socket creation based on the permission information here. + netdPermission |= INetd.PERMISSION_INTERNET; + netdPermsUids.put(uid, netdPermsUids.get(uid) | netdPermission); + } log("Users: " + mUsers.size() + ", Apps: " + mApps.size()); update(mUsers, mApps, true); sendPackagePermissionsToNetd(netdPermsUids); @@ -403,13 +411,17 @@ public class PermissionMonitor { } } - private static int getNetdPermissionMask(String[] requestedPermissions) { + private static int getNetdPermissionMask(String[] requestedPermissions, + int[] requestedPermissionsFlags) { int permissions = 0; - for (String permissionName : requestedPermissions) { - if (permissionName.equals(INTERNET)) { + if (requestedPermissions == null || requestedPermissionsFlags == null) return permissions; + for (int i = 0; i < requestedPermissions.length; i++) { + if (requestedPermissions[i].equals(INTERNET) + && ((requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED) != 0)) { permissions |= INetd.PERMISSION_INTERNET; } - if (permissionName.equals(UPDATE_DEVICE_STATS)) { + if (requestedPermissions[i].equals(UPDATE_DEVICE_STATS) + && ((requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED) != 0)) { permissions |= INetd.PERMISSION_UPDATE_DEVICE_STATS; } } diff --git a/tests/net/java/android/net/IpPrefixTest.java b/tests/net/java/android/net/IpPrefixTest.java index 3cc0e368d3..abf019afed 100644 --- a/tests/net/java/android/net/IpPrefixTest.java +++ b/tests/net/java/android/net/IpPrefixTest.java @@ -231,7 +231,6 @@ public class IpPrefixTest { assertFalse(p.contains(Address("2001:db8:f00::ace:d00e"))); assertFalse(p.contains(Address("2001:db8:f00::bad:d00d"))); assertFalse(p.contains(Address("2001:4868:4860::8888"))); - assertFalse(p.contains((InetAddress)null)); assertFalse(p.contains(Address("8.8.8.8"))); p = new IpPrefix("192.0.2.0/23"); diff --git a/tests/net/java/android/net/ipmemorystore/ParcelableTests.java b/tests/net/java/android/net/ipmemorystore/ParcelableTests.java index 76cccc9574..1a3ea6096c 100644 --- a/tests/net/java/android/net/ipmemorystore/ParcelableTests.java +++ b/tests/net/java/android/net/ipmemorystore/ParcelableTests.java @@ -44,6 +44,8 @@ public class ParcelableTests { assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable()))); builder.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4")); + // lease will expire in two hours + builder.setAssignedV4AddressExpiry(System.currentTimeMillis() + 7_200_000); // groupHint stays null this time around builder.setDnsAddresses(Collections.emptyList()); builder.setMtu(18); @@ -51,6 +53,7 @@ public class ParcelableTests { assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable()))); builder.setAssignedV4Address((Inet4Address) Inet4Address.getByName("6.7.8.9")); + builder.setAssignedV4AddressExpiry(System.currentTimeMillis() + 3_600_000); builder.setGroupHint("groupHint"); builder.setDnsAddresses(Arrays.asList( InetAddress.getByName("ACA1:652B:0911:DE8F:1200:115E:913B:AA2A"), @@ -66,7 +69,7 @@ public class ParcelableTests { // Verify that this test does not miss any new field added later. // If any field is added to NetworkAttributes it must be tested here for parceling // roundtrip. - assertEquals(4, Arrays.stream(NetworkAttributes.class.getDeclaredFields()) + assertEquals(5, Arrays.stream(NetworkAttributes.class.getDeclaredFields()) .filter(f -> !Modifier.isStatic(f.getModifiers())).count()); } diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 1151214418..44380cce1c 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -104,6 +104,7 @@ import android.net.ConnectivityManager.PacketKeepalive; import android.net.ConnectivityManager.PacketKeepaliveCallback; import android.net.ConnectivityManager.TooManyRequestsException; import android.net.ConnectivityThread; +import android.net.IDnsResolver; import android.net.INetd; import android.net.INetworkMonitor; import android.net.INetworkMonitorCallbacks; @@ -212,7 +213,6 @@ import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Consumer; import java.util.function.Predicate; /** @@ -241,6 +241,7 @@ public class ConnectivityServiceTest { private static final String CLAT_PREFIX = "v4-"; private static final String MOBILE_IFNAME = "test_rmnet_data0"; private static final String WIFI_IFNAME = "test_wlan0"; + private static final String[] EMPTY_STRING_ARRAY = new String[0]; private MockContext mServiceContext; private WrappedConnectivityService mService; @@ -257,6 +258,7 @@ public class ConnectivityServiceTest { @Mock INetworkManagementService mNetworkManagementService; @Mock INetworkStatsService mStatsService; @Mock INetworkPolicyManager mNpm; + @Mock IDnsResolver mMockDnsResolver; @Mock INetd mMockNetd; @Mock NetworkStackClient mNetworkStack; @@ -497,9 +499,8 @@ public class ConnectivityServiceTest { }; try { - doAnswer(validateAnswer).when(mNetworkMonitor).notifyNetworkConnected(); + doAnswer(validateAnswer).when(mNetworkMonitor).notifyNetworkConnected(any(), any()); doAnswer(validateAnswer).when(mNetworkMonitor).forceReevaluation(anyInt()); - doAnswer(validateAnswer).when(mNetworkMonitor).setAcceptPartialConnectivity(); } catch (RemoteException e) { fail(e.getMessage()); } @@ -1055,8 +1056,8 @@ public class ConnectivityServiceTest { public WrappedConnectivityService(Context context, INetworkManagementService netManager, INetworkStatsService statsService, INetworkPolicyManager policyManager, - IpConnectivityLog log, INetd netd) { - super(context, netManager, statsService, policyManager, log); + IpConnectivityLog log, INetd netd, IDnsResolver dnsResolver) { + super(context, netManager, statsService, policyManager, dnsResolver, log); mNetd = netd; mLingerDelayMs = TEST_LINGER_DELAY_MS; } @@ -1220,7 +1221,8 @@ public class ConnectivityServiceTest { mStatsService, mNpm, mock(IpConnectivityLog.class), - mMockNetd); + mMockNetd, + mMockDnsResolver); final ArgumentCaptor policyListenerCaptor = ArgumentCaptor.forClass(INetworkPolicyListener.class); @@ -2554,8 +2556,7 @@ public class ConnectivityServiceTest { verifyActiveNetwork(TRANSPORT_CELLULAR); } - // TODO(b/128426024): deflake and re-enable - // @Test + @Test public void testPartialConnectivity() { // Register network callback. NetworkRequest request = new NetworkRequest.Builder() @@ -2579,20 +2580,24 @@ public class ConnectivityServiceTest { assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); callback.assertNoCallback(); + // With HTTPS probe disabled, NetworkMonitor should pass the network validation with http + // probe. + mWiFiNetworkAgent.setNetworkValid(); // If the user chooses yes to use this partial connectivity wifi, switch the default // network to wifi and check if wifi becomes valid or not. mCm.setAcceptPartialConnectivity(mWiFiNetworkAgent.getNetwork(), true /* accept */, false /* always */); - // With https probe disabled, NetworkMonitor should pass the network validation with http - // probe. - mWiFiNetworkAgent.setNetworkValid(); + // If user accepts partial connectivity network, + // NetworkMonitor#setAcceptPartialConnectivity() should be called too. waitForIdle(); try { - verify(mWiFiNetworkAgent.mNetworkMonitor, - timeout(TIMEOUT_MS).times(1)).setAcceptPartialConnectivity(); + verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity(); } catch (RemoteException e) { fail(e.getMessage()); } + // Need a trigger point to let NetworkMonitor tell ConnectivityService that network is + // validated. + mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true); callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent); NetworkCapabilities nc = callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); @@ -2622,6 +2627,15 @@ public class ConnectivityServiceTest { // acceptUnvalidated is also used as setting for accepting partial networks. mWiFiNetworkAgent.explicitlySelected(true /* acceptUnvalidated */); mWiFiNetworkAgent.connect(true); + // If user accepted partial connectivity network before, + // NetworkMonitor#setAcceptPartialConnectivity() will be called in + // ConnectivityService#updateNetworkInfo(). + waitForIdle(); + try { + verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity(); + } catch (RemoteException e) { + fail(e.getMessage()); + } callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent); nc = callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); @@ -2636,23 +2650,33 @@ public class ConnectivityServiceTest { // NET_CAPABILITY_PARTIAL_CONNECTIVITY. mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); mWiFiNetworkAgent.explicitlySelected(true /* acceptUnvalidated */); + // Current design cannot send multi-testResult from NetworkMonitor to ConnectivityService. + // So, if user accepts partial connectivity, NetworkMonitor will send PARTIAL_CONNECTIVITY + // to ConnectivityService first then send VALID. Once NetworkMonitor support + // multi-testResult, this test case also need to be changed to meet the new design. mWiFiNetworkAgent.connectWithPartialConnectivity(); - callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - // TODO: If the user accepted partial connectivity, we shouldn't switch to wifi until - // NetworkMonitor detects partial connectivity - assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); - mWiFiNetworkAgent.setNetworkValid(); + // If user accepted partial connectivity network before, + // NetworkMonitor#setAcceptPartialConnectivity() will be called in + // ConnectivityService#updateNetworkInfo(). waitForIdle(); try { - verify(mWiFiNetworkAgent.mNetworkMonitor, - timeout(TIMEOUT_MS).times(1)).setAcceptPartialConnectivity(); + verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity(); } catch (RemoteException e) { fail(e.getMessage()); } + callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent); - callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiNetworkAgent); - // Wifi should be the default network. + // TODO: If the user accepted partial connectivity, we shouldn't switch to wifi until + // NetworkMonitor detects partial connectivity assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiNetworkAgent); + mWiFiNetworkAgent.setNetworkValid(); + // Need a trigger point to let NetworkMonitor tell ConnectivityService that network is + // validated. + mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true); + callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent); + mWiFiNetworkAgent.disconnect(); + callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); } @Test @@ -3022,6 +3046,47 @@ public class ConnectivityServiceTest { } } + @Test + public void testInvalidSignalStrength() { + NetworkRequest r = new NetworkRequest.Builder() + .addCapability(NET_CAPABILITY_INTERNET) + .addTransportType(TRANSPORT_WIFI) + .setSignalStrength(-75) + .build(); + // Registering a NetworkCallback with signal strength but w/o NETWORK_SIGNAL_STRENGTH_WAKEUP + // permission should get SecurityException. + try { + mCm.registerNetworkCallback(r, new NetworkCallback()); + fail("Expected SecurityException filing a callback with signal strength"); + } catch (SecurityException expected) { + // expected + } + + try { + mCm.registerNetworkCallback(r, PendingIntent.getService( + mServiceContext, 0, new Intent(), 0)); + fail("Expected SecurityException filing a callback with signal strength"); + } catch (SecurityException expected) { + // expected + } + + // Requesting a Network with signal strength should get IllegalArgumentException. + try { + mCm.requestNetwork(r, new NetworkCallback()); + fail("Expected IllegalArgumentException filing a request with signal strength"); + } catch (IllegalArgumentException expected) { + // expected + } + + try { + mCm.requestNetwork(r, PendingIntent.getService( + mServiceContext, 0, new Intent(), 0)); + fail("Expected IllegalArgumentException filing a request with signal strength"); + } catch (IllegalArgumentException expected) { + // expected + } + } + @Test public void testRegisterDefaultNetworkCallback() throws Exception { final TestNetworkCallback defaultNetworkCallback = new TestNetworkCallback(); @@ -4022,8 +4087,13 @@ public class ConnectivityServiceTest { callback3.expectStopped(); } + @FunctionalInterface + private interface ThrowingConsumer { + void accept(T t) throws Exception; + } + // Helper method to prepare the executor and run test - private void runTestWithSerialExecutors(Consumer functor) { + private void runTestWithSerialExecutors(ThrowingConsumer functor) throws Exception { final ExecutorService executorSingleThread = Executors.newSingleThreadExecutor(); final Executor executorInline = (Runnable r) -> r.run(); functor.accept(executorSingleThread); @@ -4032,23 +4102,15 @@ public class ConnectivityServiceTest { } @Test - public void testNattSocketKeepalives() { - runTestWithSerialExecutors(executor -> { - try { - doTestNattSocketKeepalivesWithExecutor(executor); - doTestNattSocketKeepalivesFdWithExecutor(executor); - } catch (Exception e) { - fail(e.getMessage()); - } - }); + public void testNattSocketKeepalives() throws Exception { + runTestWithSerialExecutors(executor -> doTestNattSocketKeepalivesWithExecutor(executor)); + runTestWithSerialExecutors(executor -> doTestNattSocketKeepalivesFdWithExecutor(executor)); } private void doTestNattSocketKeepalivesWithExecutor(Executor executor) throws Exception { // TODO: 1. Move this outside of ConnectivityServiceTest. // 2. Make test to verify that Nat-T keepalive socket is created by IpSecService. // 3. Mock ipsec service. - // 4. Find a free port instead of a fixed port. - final int srcPort = 12345; final InetAddress myIPv4 = InetAddress.getByName("192.0.2.129"); final InetAddress notMyIPv4 = InetAddress.getByName("192.0.2.35"); final InetAddress myIPv6 = InetAddress.getByName("2001:db8::1"); @@ -4059,7 +4121,8 @@ public class ConnectivityServiceTest { final int invalidKaInterval = 9; final IpSecManager mIpSec = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE); - final UdpEncapsulationSocket testSocket = mIpSec.openUdpEncapsulationSocket(srcPort); + final UdpEncapsulationSocket testSocket = mIpSec.openUdpEncapsulationSocket(); + final int srcPort = testSocket.getPort(); LinkProperties lp = new LinkProperties(); lp.setInterfaceName("wlan12"); @@ -4179,6 +4242,7 @@ public class ConnectivityServiceTest { // Check that keepalive slots start from 1 and increment. The first one gets slot 1. mWiFiNetworkAgent.setExpectedKeepaliveSlot(1); + int srcPort2 = 0; try (SocketKeepalive ka = mCm.createSocketKeepalive( myNet, testSocket, myIPv4, dstIPv4, executor, callback)) { ka.start(validKaInterval); @@ -4186,7 +4250,8 @@ public class ConnectivityServiceTest { // The second one gets slot 2. mWiFiNetworkAgent.setExpectedKeepaliveSlot(2); - final UdpEncapsulationSocket testSocket2 = mIpSec.openUdpEncapsulationSocket(6789); + final UdpEncapsulationSocket testSocket2 = mIpSec.openUdpEncapsulationSocket(); + srcPort2 = testSocket2.getPort(); TestSocketKeepaliveCallback callback2 = new TestSocketKeepaliveCallback(executor); try (SocketKeepalive ka2 = mCm.createSocketKeepalive( myNet, testSocket2, myIPv4, dstIPv4, executor, callback2)) { @@ -4204,20 +4269,18 @@ public class ConnectivityServiceTest { } } + // Check that there is no port leaked after all keepalives and sockets are closed. + assertFalse(isUdpPortInUse(srcPort)); + assertFalse(isUdpPortInUse(srcPort2)); + mWiFiNetworkAgent.disconnect(); waitFor(mWiFiNetworkAgent.getDisconnectedCV()); mWiFiNetworkAgent = null; } @Test - public void testTcpSocketKeepalives() { - runTestWithSerialExecutors(executor -> { - try { - doTestTcpSocketKeepalivesWithExecutor(executor); - } catch (Exception e) { - fail(e.getMessage()); - } - }); + public void testTcpSocketKeepalives() throws Exception { + runTestWithSerialExecutors(executor -> doTestTcpSocketKeepalivesWithExecutor(executor)); } private void doTestTcpSocketKeepalivesWithExecutor(Executor executor) throws Exception { @@ -4292,7 +4355,6 @@ public class ConnectivityServiceTest { } private void doTestNattSocketKeepalivesFdWithExecutor(Executor executor) throws Exception { - final int srcPort = 12345; final InetAddress myIPv4 = InetAddress.getByName("192.0.2.129"); final InetAddress anyIPv4 = InetAddress.getByName("0.0.0.0"); final InetAddress dstIPv4 = InetAddress.getByName("8.8.8.8"); @@ -4311,7 +4373,8 @@ public class ConnectivityServiceTest { // Prepare the target file descriptor, keep only one instance. final IpSecManager mIpSec = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE); - final UdpEncapsulationSocket testSocket = mIpSec.openUdpEncapsulationSocket(srcPort); + final UdpEncapsulationSocket testSocket = mIpSec.openUdpEncapsulationSocket(); + final int srcPort = testSocket.getPort(); final ParcelFileDescriptor testPfd = ParcelFileDescriptor.dup(testSocket.getFileDescriptor()); testSocket.close(); @@ -4759,14 +4822,14 @@ public class ConnectivityServiceTest { ArgumentCaptor tlsServers = ArgumentCaptor.forClass(String[].class); // Clear any interactions that occur as a result of CS starting up. - reset(mNetworkManagementService); + reset(mMockDnsResolver); - final String[] EMPTY_STRING_ARRAY = new String[0]; mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); waitForIdle(); - verify(mNetworkManagementService, never()).setDnsConfigurationForNetwork( - anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""), eq(EMPTY_STRING_ARRAY)); - verifyNoMoreInteractions(mNetworkManagementService); + verify(mMockDnsResolver, never()).setResolverConfiguration( + anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""), + eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY)); + verifyNoMoreInteractions(mMockDnsResolver); final LinkProperties cellLp = new LinkProperties(); cellLp.setInterfaceName(MOBILE_IFNAME); @@ -4783,28 +4846,29 @@ public class ConnectivityServiceTest { mCellNetworkAgent.connect(false); waitForIdle(); // CS tells netd about the empty DNS config for this network. - verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork( - anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""), eq(EMPTY_STRING_ARRAY)); - reset(mNetworkManagementService); + verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration( + anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""), + eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY)); + reset(mMockDnsResolver); cellLp.addDnsServer(InetAddress.getByName("2001:db8::1")); mCellNetworkAgent.sendLinkProperties(cellLp); waitForIdle(); - verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork( + verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration( anyInt(), mStringArrayCaptor.capture(), any(), any(), - eq(""), tlsServers.capture()); + eq(""), tlsServers.capture(), eq(EMPTY_STRING_ARRAY)); assertEquals(1, mStringArrayCaptor.getValue().length); assertTrue(ArrayUtils.contains(mStringArrayCaptor.getValue(), "2001:db8::1")); // Opportunistic mode. assertTrue(ArrayUtils.contains(tlsServers.getValue(), "2001:db8::1")); - reset(mNetworkManagementService); + reset(mMockDnsResolver); cellLp.addDnsServer(InetAddress.getByName("192.0.2.1")); mCellNetworkAgent.sendLinkProperties(cellLp); waitForIdle(); - verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork( + verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration( anyInt(), mStringArrayCaptor.capture(), any(), any(), - eq(""), tlsServers.capture()); + eq(""), tlsServers.capture(), eq(EMPTY_STRING_ARRAY)); assertEquals(2, mStringArrayCaptor.getValue().length); assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(), new String[]{"2001:db8::1", "192.0.2.1"})); @@ -4812,7 +4876,7 @@ public class ConnectivityServiceTest { assertEquals(2, tlsServers.getValue().length); assertTrue(ArrayUtils.containsAll(tlsServers.getValue(), new String[]{"2001:db8::1", "192.0.2.1"})); - reset(mNetworkManagementService); + reset(mMockDnsResolver); final String TLS_SPECIFIER = "tls.example.com"; final String TLS_SERVER6 = "2001:db8:53::53"; @@ -4822,22 +4886,21 @@ public class ConnectivityServiceTest { new PrivateDnsConfig(TLS_SPECIFIER, TLS_IPS).toParcel()); waitForIdle(); - verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork( + verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration( anyInt(), mStringArrayCaptor.capture(), any(), any(), - eq(TLS_SPECIFIER), eq(TLS_SERVERS)); + eq(TLS_SPECIFIER), eq(TLS_SERVERS), eq(EMPTY_STRING_ARRAY)); assertEquals(2, mStringArrayCaptor.getValue().length); assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(), new String[]{"2001:db8::1", "192.0.2.1"})); - reset(mNetworkManagementService); + reset(mMockDnsResolver); } @Test public void testPrivateDnsSettingsChange() throws Exception { - final String[] EMPTY_STRING_ARRAY = new String[0]; ArgumentCaptor tlsServers = ArgumentCaptor.forClass(String[].class); // Clear any interactions that occur as a result of CS starting up. - reset(mNetworkManagementService); + reset(mMockDnsResolver); // The default on Android is opportunistic mode ("Automatic"). setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com"); @@ -4850,9 +4913,10 @@ public class ConnectivityServiceTest { mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); waitForIdle(); // CS tells netd about the empty DNS config for this network. - verify(mNetworkManagementService, never()).setDnsConfigurationForNetwork( - anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""), eq(EMPTY_STRING_ARRAY)); - verifyNoMoreInteractions(mNetworkManagementService); + verify(mMockDnsResolver, never()).setResolverConfiguration( + anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""), + eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY)); + verifyNoMoreInteractions(mMockDnsResolver); final LinkProperties cellLp = new LinkProperties(); cellLp.setInterfaceName(MOBILE_IFNAME); @@ -4871,9 +4935,9 @@ public class ConnectivityServiceTest { mCellNetworkAgent.sendLinkProperties(cellLp); mCellNetworkAgent.connect(false); waitForIdle(); - verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork( + verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration( anyInt(), mStringArrayCaptor.capture(), any(), any(), - eq(""), tlsServers.capture()); + eq(""), tlsServers.capture(), eq(EMPTY_STRING_ARRAY)); assertEquals(2, mStringArrayCaptor.getValue().length); assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(), new String[]{"2001:db8::1", "192.0.2.1"})); @@ -4881,7 +4945,7 @@ public class ConnectivityServiceTest { assertEquals(2, tlsServers.getValue().length); assertTrue(ArrayUtils.containsAll(tlsServers.getValue(), new String[]{"2001:db8::1", "192.0.2.1"})); - reset(mNetworkManagementService); + reset(mMockDnsResolver); cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent); cellNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, mCellNetworkAgent); @@ -4893,26 +4957,26 @@ public class ConnectivityServiceTest { assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName()); setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com"); - verify(mNetworkManagementService, times(1)).setDnsConfigurationForNetwork( + verify(mMockDnsResolver, times(1)).setResolverConfiguration( anyInt(), mStringArrayCaptor.capture(), any(), any(), - eq(""), eq(EMPTY_STRING_ARRAY)); + eq(""), eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY)); assertEquals(2, mStringArrayCaptor.getValue().length); assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(), new String[]{"2001:db8::1", "192.0.2.1"})); - reset(mNetworkManagementService); + reset(mMockDnsResolver); cellNetworkCallback.assertNoCallback(); setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com"); - verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork( + verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration( anyInt(), mStringArrayCaptor.capture(), any(), any(), - eq(""), tlsServers.capture()); + eq(""), tlsServers.capture(), eq(EMPTY_STRING_ARRAY)); assertEquals(2, mStringArrayCaptor.getValue().length); assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(), new String[]{"2001:db8::1", "192.0.2.1"})); assertEquals(2, tlsServers.getValue().length); assertTrue(ArrayUtils.containsAll(tlsServers.getValue(), new String[]{"2001:db8::1", "192.0.2.1"})); - reset(mNetworkManagementService); + reset(mMockDnsResolver); cellNetworkCallback.assertNoCallback(); setPrivateDnsSettings(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, "strict.example.com"); @@ -5743,6 +5807,7 @@ public class ConnectivityServiceTest { cellLp.addRoute(new RouteInfo((IpPrefix) null, myIpv6.getAddress(), MOBILE_IFNAME)); cellLp.addRoute(new RouteInfo(myIpv6, null, MOBILE_IFNAME)); reset(mNetworkManagementService); + reset(mMockDnsResolver); when(mNetworkManagementService.getInterfaceConfig(CLAT_PREFIX + MOBILE_IFNAME)) .thenReturn(getClatInterfaceConfig(myIpv4)); @@ -5750,7 +5815,7 @@ public class ConnectivityServiceTest { mCellNetworkAgent.sendLinkProperties(cellLp); mCellNetworkAgent.connect(true); networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - verify(mMockNetd, times(1)).resolverStartPrefix64Discovery(cellNetId); + verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId); // Switching default network updates TCP buffer sizes. verifyTcpBufferSizeChange(ConnectivityService.DEFAULT_TCP_BUFFER_SIZES); @@ -5760,17 +5825,22 @@ public class ConnectivityServiceTest { cellLp.addLinkAddress(myIpv4); mCellNetworkAgent.sendLinkProperties(cellLp); networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent); - verify(mMockNetd, times(1)).resolverStopPrefix64Discovery(cellNetId); + verify(mMockDnsResolver, times(1)).stopPrefix64Discovery(cellNetId); + verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration( + eq(cellNetId), eq(EMPTY_STRING_ARRAY), any(), any(), + eq(""), eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY)); verifyNoMoreInteractions(mMockNetd); + verifyNoMoreInteractions(mMockDnsResolver); reset(mMockNetd); + reset(mMockDnsResolver); // Remove IPv4 address. Expect prefix discovery to be started again. cellLp.removeLinkAddress(myIpv4); cellLp.removeRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME)); mCellNetworkAgent.sendLinkProperties(cellLp); networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent); - verify(mMockNetd, times(1)).resolverStartPrefix64Discovery(cellNetId); + verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId); // When NAT64 prefix discovery succeeds, LinkProperties are updated and clatd is started. Nat464Xlat clat = mService.getNat464Xlat(mCellNetworkAgent); @@ -5800,6 +5870,12 @@ public class ConnectivityServiceTest { assertNotEquals(stackedLpsAfterChange, Collections.EMPTY_LIST); assertEquals(makeClatLinkProperties(myIpv4), stackedLpsAfterChange.get(0)); + verify(mMockDnsResolver, times(1)).setResolverConfiguration( + eq(cellNetId), mStringArrayCaptor.capture(), any(), any(), + eq(""), eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY)); + assertEquals(1, mStringArrayCaptor.getValue().length); + assertTrue(ArrayUtils.contains(mStringArrayCaptor.getValue(), "8.8.8.8")); + // Add ipv4 address, expect that clatd and prefix discovery are stopped and stacked // linkproperties are cleaned up. cellLp.addLinkAddress(myIpv4); @@ -5807,7 +5883,7 @@ public class ConnectivityServiceTest { mCellNetworkAgent.sendLinkProperties(cellLp); networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent); verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME); - verify(mMockNetd, times(1)).resolverStopPrefix64Discovery(cellNetId); + verify(mMockDnsResolver, times(1)).stopPrefix64Discovery(cellNetId); // As soon as stop is called, the linkproperties lose the stacked interface. networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent); @@ -5822,7 +5898,9 @@ public class ConnectivityServiceTest { networkCallback.assertNoCallback(); verifyNoMoreInteractions(mMockNetd); + verifyNoMoreInteractions(mMockDnsResolver); reset(mMockNetd); + reset(mMockDnsResolver); // Stopping prefix discovery causes netd to tell us that the NAT64 prefix is gone. mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, false /* added */, @@ -5836,7 +5914,7 @@ public class ConnectivityServiceTest { cellLp.removeDnsServer(InetAddress.getByName("8.8.8.8")); mCellNetworkAgent.sendLinkProperties(cellLp); networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent); - verify(mMockNetd, times(1)).resolverStartPrefix64Discovery(cellNetId); + verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId); mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */, kNat64PrefixString, 96); networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent); @@ -5919,6 +5997,7 @@ public class ConnectivityServiceTest { // Disconnect cell reset(mNetworkManagementService); + reset(mMockNetd); mCellNetworkAgent.disconnect(); networkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent); // LOST callback is triggered earlier than removing idle timer. Broadcast should also be @@ -5926,8 +6005,9 @@ public class ConnectivityServiceTest { // unexpectedly before network being removed. waitForIdle(); verify(mNetworkManagementService, times(0)).removeIdleTimer(eq(MOBILE_IFNAME)); - verify(mNetworkManagementService, times(1)).removeNetwork( - eq(mCellNetworkAgent.getNetwork().netId)); + verify(mMockNetd, times(1)).networkDestroy(eq(mCellNetworkAgent.getNetwork().netId)); + verify(mMockDnsResolver, times(1)) + .clearResolverConfiguration(eq(mCellNetworkAgent.getNetwork().netId)); // Disconnect wifi ConditionVariable cv = waitForConnectivityBroadcasts(1); diff --git a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java index 15ba43df83..8fa0ab979a 100644 --- a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java +++ b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java @@ -29,13 +29,13 @@ import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.when; import android.content.Context; +import android.net.IDnsResolver; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; import android.net.RouteInfo; import android.net.shared.PrivateDnsConfig; -import android.os.INetworkManagementService; import android.provider.Settings; import android.test.mock.MockContentResolver; @@ -73,7 +73,7 @@ public class DnsManagerTest { MockContentResolver mContentResolver; @Mock Context mCtx; - @Mock INetworkManagementService mNMService; + @Mock IDnsResolver mMockDnsResolver; @Mock MockableSystemProperties mSystemProperties; @Before @@ -83,7 +83,7 @@ public class DnsManagerTest { mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); when(mCtx.getContentResolver()).thenReturn(mContentResolver); - mDnsManager = new DnsManager(mCtx, mNMService, mSystemProperties); + mDnsManager = new DnsManager(mCtx, mMockDnsResolver, mSystemProperties); // Clear the private DNS settings Settings.Global.putString(mContentResolver, PRIVATE_DNS_DEFAULT_MODE, ""); diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java index 6de4aa1be1..142769f613 100644 --- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java @@ -32,6 +32,7 @@ import android.app.PendingIntent; import android.content.Context; import android.content.res.Resources; import android.net.ConnectivityManager; +import android.net.IDnsResolver; import android.net.INetd; import android.net.Network; import android.net.NetworkCapabilities; @@ -69,6 +70,7 @@ public class LingerMonitorTest { LingerMonitor mMonitor; @Mock ConnectivityService mConnService; + @Mock IDnsResolver mDnsResolver; @Mock INetd mNetd; @Mock INetworkManagementService mNMS; @Mock Context mCtx; @@ -353,7 +355,7 @@ public class LingerMonitorTest { caps.addCapability(0); caps.addTransportType(transport); NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null, - caps, 50, mCtx, null, mMisc, mConnService, mNetd, mNMS, + caps, 50, mCtx, null, mMisc, mConnService, mNetd, mDnsResolver, mNMS, NetworkFactory.SerialNumber.NONE); nai.everValidated = true; return nai; diff --git a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java index cc09fb7ba6..b709af1a02 100644 --- a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java +++ b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java @@ -27,6 +27,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import android.net.ConnectivityManager; +import android.net.IDnsResolver; import android.net.INetd; import android.net.InterfaceConfiguration; import android.net.IpPrefix; @@ -63,6 +64,7 @@ public class Nat464XlatTest { @Mock ConnectivityService mConnectivity; @Mock NetworkMisc mMisc; + @Mock IDnsResolver mDnsResolver; @Mock INetd mNetd; @Mock INetworkManagementService mNms; @Mock InterfaceConfiguration mConfig; @@ -72,7 +74,7 @@ public class Nat464XlatTest { Handler mHandler; Nat464Xlat makeNat464Xlat() { - return new Nat464Xlat(mNai, mNetd, mNms) { + return new Nat464Xlat(mNai, mNetd, mDnsResolver, mNms) { @Override protected int getNetId() { return NETID; } @@ -205,7 +207,7 @@ public class Nat464XlatTest { verify(mNms).unregisterObserver(eq(nat)); assertTrue(c.getValue().getStackedLinks().isEmpty()); assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE)); - verify(mNetd).resolverStopPrefix64Discovery(eq(NETID)); + verify(mDnsResolver).stopPrefix64Discovery(eq(NETID)); assertIdle(nat); // Stacked interface removed notification arrives and is ignored. @@ -331,7 +333,7 @@ public class Nat464XlatTest { verify(mNetd).clatdStop(eq(BASE_IFACE)); verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture()); verify(mNms).unregisterObserver(eq(nat)); - verify(mNetd).resolverStopPrefix64Discovery(eq(NETID)); + verify(mDnsResolver).stopPrefix64Discovery(eq(NETID)); assertTrue(c.getValue().getStackedLinks().isEmpty()); assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE)); assertIdle(nat); @@ -358,7 +360,7 @@ public class Nat464XlatTest { verify(mNetd).clatdStop(eq(BASE_IFACE)); verify(mNms).unregisterObserver(eq(nat)); - verify(mNetd).resolverStopPrefix64Discovery(eq(NETID)); + verify(mDnsResolver).stopPrefix64Discovery(eq(NETID)); assertIdle(nat); // In-flight interface up notification arrives: no-op @@ -390,7 +392,7 @@ public class Nat464XlatTest { verify(mNetd).clatdStop(eq(BASE_IFACE)); verify(mNms).unregisterObserver(eq(nat)); - verify(mNetd).resolverStopPrefix64Discovery(eq(NETID)); + verify(mDnsResolver).stopPrefix64Discovery(eq(NETID)); assertIdle(nat); verifyNoMoreInteractions(mNetd, mNms, mConnectivity); diff --git a/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java b/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java index dc20185430..fb84611cb6 100644 --- a/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java +++ b/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java @@ -57,6 +57,7 @@ public class NetworkAttributesTest { final NetworkAttributes na = new NetworkAttributes( (Inet4Address) Inet4Address.getByAddress(new byte[] {1, 2, 3, 4}), + System.currentTimeMillis() + 7_200_000, "some hint", Arrays.asList(Inet4Address.getByAddress(new byte[] {5, 6, 7, 8}), Inet4Address.getByAddress(new byte[] {9, 0, 1, 2})),