Merge "Fix comment on StaticIpConfiguration#getDomains"
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 4a64128..2906710 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2617,7 +2617,7 @@
/**
* Start listening to tethering change events. Any new added callback will receive the last
- * tethering status right away. If callback is registered when tethering loses its upstream or
+ * tethering status right away. If callback is registered when tethering has no upstream or
* disabled, {@link OnTetheringEventCallback#onUpstreamChanged} will immediately be called
* with a null argument. The same callback object cannot be registered twice.
*
@@ -3234,7 +3234,7 @@
*
* @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.
@@ -3247,8 +3247,9 @@
* @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.
@@ -3272,7 +3273,7 @@
*
* @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
@@ -3288,7 +3289,7 @@
* 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
@@ -3296,7 +3297,7 @@
*
* @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
@@ -3316,8 +3317,8 @@
* @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
@@ -3326,7 +3327,8 @@
* @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
@@ -3337,7 +3339,7 @@
* 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
@@ -3345,7 +3347,7 @@
* 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 f9e0af2..06c32c6 100644
--- a/core/java/android/net/DnsResolver.java
+++ b/core/java/android/net/DnsResolver.java
@@ -22,6 +22,10 @@
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.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 @@
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 @@
* 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
@@ -211,21 +222,26 @@
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, lock);
- registerFDListener(executor, queryfd, callback, cancellationSignal, lock);
+ 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
@@ -249,12 +265,152 @@
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, lock);
- registerFDListener(executor, queryfd, callback, cancellationSignal, lock);
+ private class InetAddressAnswerAccumulator extends InetAddressAnswerCallback {
+ private final List<InetAddress> 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<InetAddress> 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 <T> void registerFDListener(@NonNull Executor executor,
@@ -271,7 +427,7 @@
}
byte[] answerbuf = null;
try {
- answerbuf = resNetworkResult(fd);
+ answerbuf = resNetworkResult(fd); // Closes fd, marks it invalid.
} catch (ErrnoException e) {
Log.e(TAG, "resNetworkResult:" + e.toString());
answerCallback.onQueryException(e);
@@ -291,19 +447,53 @@
});
}
- private void maybeAddCancellationSignal(@Nullable CancellationSignal cancellationSignal,
+ 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) {
- if (cancellationSignal == null) return;
cancellationSignal.setOnCancelListener(() -> {
synchronized (lock) {
- if (!queryfd.valid()) return;
- Looper.getMainLooper().getQueue()
- .removeOnFileDescriptorEventListener(queryfd);
- resNetworkCancel(queryfd);
+ 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 {
private static final String TAG = "DnsResolver.DnsAddressAnswer";
private static final boolean DBG = false;
diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java
index b4f3a28..416157c 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 @@
*
* @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 @@
*/
@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 @@
*
* @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 @@
*
* @return the address in the form of a byte array.
*/
- public byte[] getRawAddress() {
+ public @NonNull byte[] getRawAddress() {
return address.clone();
}
@@ -175,6 +176,7 @@
*
* @return the prefix length.
*/
+ @IntRange(from = 0, to = 128)
public int getPrefixLength() {
return prefixLength;
}
@@ -183,10 +185,10 @@
* 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 @@
* @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 78b4665..f17adea 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_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 @@
* 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 @@
*/
@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 @@
* 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 @@
* @param interfaceAddress The interface address.
* @hide
*/
- public LinkAddress(InterfaceAddress interfaceAddress) {
+ public LinkAddress(@NonNull InterfaceAddress interfaceAddress) {
this(interfaceAddress.getAddress(),
interfaceAddress.getNetworkPrefixLength());
}
@@ -306,6 +309,7 @@
/**
* Returns the prefix length of this {@code LinkAddress}.
*/
+ @IntRange(from = 0, to = 128)
public int getPrefixLength() {
return prefixLength;
}
@@ -316,6 +320,7 @@
* @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 03d6d48..ad67763 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -316,9 +316,6 @@
@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 @@
@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 3a41a07..acafa13 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 @@
* current value. A value of {@code SIGNAL_STRENGTH_UNSPECIFIED} means no value when
* received and has no effect when requesting a callback.
*
+ * <p>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/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index d2d886b..dd3fff8 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -24,7 +24,6 @@
import android.util.Pair;
import java.io.FileDescriptor;
-import java.io.IOException;
import java.math.BigInteger;
import java.net.Inet4Address;
import java.net.Inet6Address;
@@ -45,32 +44,6 @@
private static final String TAG = "NetworkUtils";
/**
- * Attaches a socket filter that accepts DHCP packets to the given socket.
- */
- @UnsupportedAppUsage
- public native static void attachDhcpFilter(FileDescriptor fd) throws SocketException;
-
- /**
- * Attaches a socket filter that accepts ICMPv6 router advertisements to the given socket.
- * @param fd the socket's {@link FileDescriptor}.
- * @param packetType the hardware address type, one of ARPHRD_*.
- */
- @UnsupportedAppUsage
- public native static void attachRaFilter(FileDescriptor fd, int packetType) throws SocketException;
-
- /**
- * Attaches a socket filter that accepts L2-L4 signaling traffic required for IP connectivity.
- *
- * This includes: all ARP, ICMPv6 RS/RA/NS/NA messages, and DHCPv4 exchanges.
- *
- * @param fd the socket's {@link FileDescriptor}.
- * @param packetType the hardware address type, one of ARPHRD_*.
- */
- @UnsupportedAppUsage
- public native static void attachControlPacketFilter(FileDescriptor fd, int packetType)
- throws SocketException;
-
- /**
* Attaches a socket filter that drops all of incoming packets.
* @param fd the socket's {@link FileDescriptor}.
*/
@@ -178,18 +151,6 @@
public static native void resNetworkCancel(FileDescriptor fd);
/**
- * Add an entry into the ARP cache.
- */
- public static void addArpEntry(Inet4Address ipv4Addr, MacAddress ethAddr, String ifname,
- FileDescriptor fd) throws IOException {
- addArpEntry(ethAddr.toByteArray(), ipv4Addr.getAddress(), ifname, fd);
- }
-
- private static native void addArpEntry(byte[] ethAddr, byte[] netAddr, String ifname,
- FileDescriptor fd) throws IOException;
-
-
- /**
* Get the tcp repair window associated with the {@code fd}.
*
* @param fd the tcp socket's {@link FileDescriptor}.
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index 24d9b8e..fdd904a 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.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 @@
* (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 @@
* @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 @@
}
/**
- * @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 <code>0.0.0.0</code>
+ * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default
+ * route <code>::/0</code> if gateway is an instance of {@link Inet6Address}.
+ * <p>
+ * Destination and gateway may not both be null.
+ *
+ * @param destination the destination address and prefix in an {@link IpPrefix}
+ * @param gateway the {@link InetAddress} to route packets through
+ * @param iface the interface name to send packets on
+ *
+ * @hide
*/
@UnsupportedAppUsage
- 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 @@
* @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 @@
*
* @hide
*/
- public RouteInfo(IpPrefix destination, InetAddress gateway) {
+ public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway) {
this(destination, gateway, null);
}
@@ -215,7 +247,7 @@
* 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 @@
* @hide
*/
@UnsupportedAppUsage
- public RouteInfo(InetAddress gateway) {
+ public RouteInfo(@NonNull InetAddress gateway) {
this((IpPrefix) null, gateway, null);
}
@@ -239,35 +271,36 @@
*
* @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 @@
*
* @return {@link IpPrefix} specifying the destination. This is never {@code null}.
*/
+ @NonNull
public IpPrefix getDestination() {
return mDestination;
}
@@ -298,6 +332,7 @@
* 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 @@
* @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 @@
*
* @return The name of the interface used for this route.
*/
+ @Nullable
public String getInterface() {
return mInterface;
}
@@ -330,6 +367,7 @@
*/
@TestApi
@SystemApi
+ @RouteType
public int getType() {
return mType;
}
@@ -401,6 +439,7 @@
* @hide
*/
@UnsupportedAppUsage
+ @Nullable
public static RouteInfo selectBestRoute(Collection<RouteInfo> 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 17a03c7..4dd2ace 100644
--- a/core/java/android/net/apf/ApfCapabilities.java
+++ b/core/java/android/net/apf/ApfCapabilities.java
@@ -19,14 +19,17 @@
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 @@
}
/**
- * 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 @@
/**
* @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 82acf6f..dd754f3 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -48,17 +48,6 @@
namespace android {
-static const uint32_t kEtherTypeOffset = offsetof(ether_header, ether_type);
-static const uint32_t kEtherHeaderLen = sizeof(ether_header);
-static const uint32_t kIPv4Protocol = kEtherHeaderLen + offsetof(iphdr, protocol);
-static const uint32_t kIPv4FlagsOffset = kEtherHeaderLen + offsetof(iphdr, frag_off);
-static const uint32_t kIPv6NextHeader = kEtherHeaderLen + offsetof(ip6_hdr, ip6_nxt);
-static const uint32_t kIPv6PayloadStart = kEtherHeaderLen + sizeof(ip6_hdr);
-static const uint32_t kICMPv6TypeOffset = kIPv6PayloadStart + offsetof(icmp6_hdr, icmp6_type);
-static const uint32_t kUDPSrcPortIndirectOffset = kEtherHeaderLen + offsetof(udphdr, source);
-static const uint32_t kUDPDstPortIndirectOffset = kEtherHeaderLen + offsetof(udphdr, dest);
-static const uint16_t kDhcpClientPort = 68;
-
constexpr int MAXPACKETSIZE = 8 * 1024;
// FrameworkListener limits the size of commands to 1024 bytes. TODO: fix this.
constexpr int MAXCMDSIZE = 1024;
@@ -84,149 +73,6 @@
env->Throw(reinterpret_cast<jthrowable>(exception));
}
-static void android_net_utils_attachDhcpFilter(JNIEnv *env, jobject clazz, jobject javaFd)
-{
- struct sock_filter filter_code[] = {
- // Check the protocol is UDP.
- BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kIPv4Protocol),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_UDP, 0, 6),
-
- // Check this is not a fragment.
- BPF_STMT(BPF_LD | BPF_H | BPF_ABS, kIPv4FlagsOffset),
- BPF_JUMP(BPF_JMP | BPF_JSET | BPF_K, IP_OFFMASK, 4, 0),
-
- // Get the IP header length.
- BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, kEtherHeaderLen),
-
- // Check the destination port.
- BPF_STMT(BPF_LD | BPF_H | BPF_IND, kUDPDstPortIndirectOffset),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, kDhcpClientPort, 0, 1),
-
- // Accept or reject.
- BPF_STMT(BPF_RET | BPF_K, 0xffff),
- BPF_STMT(BPF_RET | BPF_K, 0)
- };
- struct sock_fprog filter = {
- sizeof(filter_code) / sizeof(filter_code[0]),
- filter_code,
- };
-
- int fd = jniGetFDFromFileDescriptor(env, javaFd);
- if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
- jniThrowExceptionFmt(env, "java/net/SocketException",
- "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
- }
-}
-
-static void android_net_utils_attachRaFilter(JNIEnv *env, jobject clazz, jobject javaFd,
- jint hardwareAddressType)
-{
- if (hardwareAddressType != ARPHRD_ETHER) {
- jniThrowExceptionFmt(env, "java/net/SocketException",
- "attachRaFilter only supports ARPHRD_ETHER");
- return;
- }
-
- struct sock_filter filter_code[] = {
- // Check IPv6 Next Header is ICMPv6.
- BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kIPv6NextHeader),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_ICMPV6, 0, 3),
-
- // Check ICMPv6 type is Router Advertisement.
- BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kICMPv6TypeOffset),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ND_ROUTER_ADVERT, 0, 1),
-
- // Accept or reject.
- BPF_STMT(BPF_RET | BPF_K, 0xffff),
- BPF_STMT(BPF_RET | BPF_K, 0)
- };
- struct sock_fprog filter = {
- sizeof(filter_code) / sizeof(filter_code[0]),
- filter_code,
- };
-
- int fd = jniGetFDFromFileDescriptor(env, javaFd);
- if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
- jniThrowExceptionFmt(env, "java/net/SocketException",
- "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
- }
-}
-
-// TODO: Move all this filter code into libnetutils.
-static void android_net_utils_attachControlPacketFilter(
- JNIEnv *env, jobject clazz, jobject javaFd, jint hardwareAddressType) {
- if (hardwareAddressType != ARPHRD_ETHER) {
- jniThrowExceptionFmt(env, "java/net/SocketException",
- "attachControlPacketFilter only supports ARPHRD_ETHER");
- return;
- }
-
- // Capture all:
- // - ARPs
- // - DHCPv4 packets
- // - Router Advertisements & Solicitations
- // - Neighbor Advertisements & Solicitations
- //
- // tcpdump:
- // arp or
- // '(ip and udp port 68)' or
- // '(icmp6 and ip6[40] >= 133 and ip6[40] <= 136)'
- struct sock_filter filter_code[] = {
- // Load the link layer next payload field.
- BPF_STMT(BPF_LD | BPF_H | BPF_ABS, kEtherTypeOffset),
-
- // Accept all ARP.
- // TODO: Figure out how to better filter ARPs on noisy networks.
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ETHERTYPE_ARP, 16, 0),
-
- // If IPv4:
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ETHERTYPE_IP, 0, 9),
-
- // Check the protocol is UDP.
- BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kIPv4Protocol),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_UDP, 0, 14),
-
- // Check this is not a fragment.
- BPF_STMT(BPF_LD | BPF_H | BPF_ABS, kIPv4FlagsOffset),
- BPF_JUMP(BPF_JMP | BPF_JSET | BPF_K, IP_OFFMASK, 12, 0),
-
- // Get the IP header length.
- BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, kEtherHeaderLen),
-
- // Check the source port.
- BPF_STMT(BPF_LD | BPF_H | BPF_IND, kUDPSrcPortIndirectOffset),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, kDhcpClientPort, 8, 0),
-
- // Check the destination port.
- BPF_STMT(BPF_LD | BPF_H | BPF_IND, kUDPDstPortIndirectOffset),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, kDhcpClientPort, 6, 7),
-
- // IPv6 ...
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ETHERTYPE_IPV6, 0, 6),
- // ... check IPv6 Next Header is ICMPv6 (ignore fragments), ...
- BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kIPv6NextHeader),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_ICMPV6, 0, 4),
- // ... and check the ICMPv6 type is one of RS/RA/NS/NA.
- BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kICMPv6TypeOffset),
- BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, ND_ROUTER_SOLICIT, 0, 2),
- BPF_JUMP(BPF_JMP | BPF_JGT | BPF_K, ND_NEIGHBOR_ADVERT, 1, 0),
-
- // Accept or reject.
- BPF_STMT(BPF_RET | BPF_K, 0xffff),
- BPF_STMT(BPF_RET | BPF_K, 0)
- };
- struct sock_fprog filter = {
- sizeof(filter_code) / sizeof(filter_code[0]),
- filter_code,
- };
-
- int fd = jniGetFDFromFileDescriptor(env, javaFd);
- if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
- jniThrowExceptionFmt(env, "java/net/SocketException",
- "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
- }
-}
-
static void android_net_utils_attachDropAllBPFFilter(JNIEnv *env, jobject clazz, jobject javaFd)
{
struct sock_filter filter_code[] = {
@@ -389,46 +235,6 @@
return true;
}
-static void android_net_utils_addArpEntry(JNIEnv *env, jobject thiz, jbyteArray ethAddr,
- jbyteArray ipv4Addr, jstring ifname, jobject javaFd)
-{
- struct arpreq req = {};
- struct sockaddr_in& netAddrStruct = *reinterpret_cast<sockaddr_in*>(&req.arp_pa);
- struct sockaddr& ethAddrStruct = req.arp_ha;
-
- ethAddrStruct.sa_family = ARPHRD_ETHER;
- if (!checkLenAndCopy(env, ethAddr, ETH_ALEN, ethAddrStruct.sa_data)) {
- jniThrowException(env, "java/io/IOException", "Invalid ethAddr length");
- return;
- }
-
- netAddrStruct.sin_family = AF_INET;
- if (!checkLenAndCopy(env, ipv4Addr, sizeof(in_addr), &netAddrStruct.sin_addr)) {
- jniThrowException(env, "java/io/IOException", "Invalid ipv4Addr length");
- return;
- }
-
- int ifLen = env->GetStringLength(ifname);
- // IFNAMSIZ includes the terminating NULL character
- if (ifLen >= IFNAMSIZ) {
- jniThrowException(env, "java/io/IOException", "ifname too long");
- return;
- }
- env->GetStringUTFRegion(ifname, 0, ifLen, req.arp_dev);
-
- req.arp_flags = ATF_COM; // Completed entry (ha valid)
- int fd = jniGetFDFromFileDescriptor(env, javaFd);
- if (fd < 0) {
- jniThrowExceptionFmt(env, "java/io/IOException", "Invalid file descriptor");
- return;
- }
- // See also: man 7 arp
- if (ioctl(fd, SIOCSARP, &req)) {
- jniThrowExceptionFmt(env, "java/io/IOException", "ioctl error: %s", strerror(errno));
- return;
- }
-}
-
static jobject android_net_utils_resNetworkQuery(JNIEnv *env, jobject thiz, jint netId,
jstring dname, jint ns_class, jint ns_type, jint flags) {
const jsize javaCharsCount = env->GetStringLength(dname);
@@ -542,10 +348,6 @@
{ "bindSocketToNetwork", "(II)I", (void*) android_net_utils_bindSocketToNetwork },
{ "protectFromVpn", "(I)Z", (void*)android_net_utils_protectFromVpn },
{ "queryUserAccess", "(II)Z", (void*)android_net_utils_queryUserAccess },
- { "addArpEntry", "([B[BLjava/lang/String;Ljava/io/FileDescriptor;)V", (void*) android_net_utils_addArpEntry },
- { "attachDhcpFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDhcpFilter },
- { "attachRaFilter", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_attachRaFilter },
- { "attachControlPacketFilter", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_attachControlPacketFilter },
{ "attachDropAllBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDropAllBPFFilter },
{ "detachBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_detachBPFFilter },
{ "getTcpRepairWindow", "(Ljava/io/FileDescriptor;)Landroid/net/TcpRepairWindow;", (void*) android_net_utils_getTcpRepairWindow },
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 58807de..524548f 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.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;
@@ -107,7 +108,6 @@
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.NetworkEvent;
import android.net.netlink.InetDiagMessage;
-import android.net.shared.NetworkMonitorUtils;
import android.net.shared.PrivateDnsConfig;
import android.net.util.MultinetworkPolicyTracker;
import android.net.util.NetdService;
@@ -132,6 +132,7 @@
import android.os.ShellCallback;
import android.os.ShellCommand;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
@@ -236,6 +237,16 @@
private static final boolean LOGD_BLOCKED_NETWORKINFO = true;
+ /**
+ * Default URL to use for {@link #getCaptivePortalServerUrl()}. This should not be changed
+ * by OEMs for configuration purposes, as this value is overridden by
+ * Settings.Global.CAPTIVE_PORTAL_HTTP_URL.
+ * R.string.config_networkCaptivePortalServerUrl should be overridden instead for this purpose
+ * (preferably via runtime resource overlays).
+ */
+ private static final String DEFAULT_CAPTIVE_PORTAL_HTTP_URL =
+ "http://connectivitycheck.gstatic.com/generate_204";
+
// TODO: create better separation between radio types and network types
// how long to wait before switching back to a radio's default network
@@ -294,6 +305,8 @@
private INetworkManagementService mNMS;
@VisibleForTesting
+ protected IDnsResolver mDnsResolver;
+ @VisibleForTesting
protected INetd mNetd;
private INetworkStatsService mStatsService;
private INetworkPolicyManager mPolicyManager;
@@ -525,6 +538,11 @@
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 +828,14 @@
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 +872,7 @@
mPolicyManagerInternal = checkNotNull(
LocalServices.getService(NetworkPolicyManagerInternal.class),
"missing NetworkPolicyManagerInternal");
+ mDnsResolver = checkNotNull(dnsresolver, "missing IDnsResolver");
mProxyTracker = makeProxyTracker();
mNetd = NetdService.getInstance();
@@ -941,7 +961,7 @@
mTethering = makeTethering();
- mPermissionMonitor = new PermissionMonitor(mContext, mNMS);
+ mPermissionMonitor = new PermissionMonitor(mContext, mNMS, mNetd);
// Set up the listener for user state for creating user VPNs.
// Should run on mHandler to avoid any races.
@@ -1006,7 +1026,7 @@
mMultipathPolicyTracker = new MultipathPolicyTracker(mContext, mHandler);
- mDnsManager = new DnsManager(mContext, mNMS, mSystemProperties);
+ mDnsManager = new DnsManager(mContext, mDnsResolver, mSystemProperties);
registerPrivateDnsSettingsCallbacks();
}
@@ -1618,8 +1638,11 @@
*/
private boolean disallowedBecauseSystemCaller() {
// TODO: start throwing a SecurityException when GnssLocationProvider stops calling
- // requestRouteToHost.
- if (isSystem(Binder.getCallingUid())) {
+ // requestRouteToHost. In Q, GnssLocationProvider is changed to not call requestRouteToHost
+ // for devices launched with Q and above. However, existing devices upgrading to Q and
+ // above must continued to be supported for few more releases.
+ if (isSystem(Binder.getCallingUid()) && SystemProperties.getInt(
+ "ro.product.first_api_level", 0) > Build.VERSION_CODES.P) {
log("This method exists only for app backwards compatibility"
+ " and must not be called by system services.");
return true;
@@ -1751,17 +1774,12 @@
// the caller thread of registerNetworkAgent. Thus, it's not allowed to register netd
// event callback for certain nai. e.g. cellular. Register here to pass to
// NetworkMonitor instead.
- // TODO: Move the Dns Event to NetworkMonitor. Use Binder.clearCallingIdentity() in
- // registerNetworkAgent to have NetworkMonitor created with system process as design
- // expectation. Also, NetdEventListenerService only allow one callback from each
- // caller type. Need to re-factor NetdEventListenerService to allow multiple
- // NetworkMonitor registrants.
+ // TODO: Move the Dns Event to NetworkMonitor. NetdEventListenerService only allow one
+ // callback from each caller type. Need to re-factor NetdEventListenerService to allow
+ // multiple NetworkMonitor registrants.
if (nai != null && nai.satisfies(mDefaultRequest)) {
- try {
- nai.networkMonitor().notifyDnsResponse(returnCode);
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
+ Binder.withCleanCallingIdentity(() ->
+ nai.networkMonitor().notifyDnsResponse(returnCode));
}
}
@@ -1882,6 +1900,15 @@
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 +1983,12 @@
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 +3054,9 @@
// 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 +3761,6 @@
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;
}
@@ -4959,13 +4982,19 @@
}
}
- // 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<Integer> getSignalStrengthThresholds(NetworkAgentInfo nai) {
@@ -5379,10 +5408,10 @@
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;
@@ -5413,15 +5442,6 @@
synchronized (mNetworkForNetId) {
mNetworkForNetId.put(nai.network.netId, nai);
}
- synchronized (this) {
- if (mSystemReady) {
- try {
- networkMonitor.notifySystemReady();
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
- }
- }
try {
networkMonitor.start();
@@ -5475,12 +5495,12 @@
// 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);
}
}
@@ -5708,7 +5728,7 @@
final NetworkCapabilities prevNc;
synchronized (nai) {
prevNc = nai.networkCapabilities;
- nai.networkCapabilities = newNc;
+ nai.setNetworkCapabilities(newNc);
}
updateUids(nai, prevNc, newNc);
@@ -5723,11 +5743,6 @@
// 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);
}
@@ -5986,11 +6001,6 @@
}
if (capabilitiesChanged) {
- try {
- nai.networkMonitor().notifyNetworkCapabilitiesChanged();
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
}
@@ -6387,6 +6397,11 @@
Slog.wtf(TAG, networkAgent.name() + " connected with null LinkProperties");
}
+ // NetworkCapabilities need to be set before sending the private DNS config to
+ // NetworkMonitor, otherwise NetworkMonitor cannot determine if validation is required.
+ synchronized (networkAgent) {
+ networkAgent.setNetworkCapabilities(networkAgent.networkCapabilities);
+ }
handlePerNetworkPrivateDnsConfig(networkAgent, mDnsManager.getPrivateDnsConfig());
updateLinkProperties(networkAgent, new LinkProperties(networkAgent.linkProperties),
null);
@@ -6399,7 +6414,8 @@
if (networkAgent.networkMisc.acceptPartialConnectivity) {
networkAgent.networkMonitor().setAcceptPartialConnectivity();
}
- networkAgent.networkMonitor().notifyNetworkConnected();
+ networkAgent.networkMonitor().notifyNetworkConnected(
+ networkAgent.linkProperties, networkAgent.networkCapabilities);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
@@ -6541,7 +6557,7 @@
uid, newRules, metered, mRestrictBackground);
}
if (oldBlocked == newBlocked) {
- return;
+ continue;
}
final int arg = encodeBool(newBlocked);
for (int i = 0; i < nai.numNetworkRequests(); i++) {
@@ -6699,9 +6715,20 @@
@Override
public String getCaptivePortalServerUrl() {
enforceConnectivityInternalPermission();
- final String defaultUrl = mContext.getResources().getString(
- R.string.config_networkDefaultCaptivePortalServerUrl);
- return NetworkMonitorUtils.getCaptivePortalServerHttpUrl(mContext, defaultUrl);
+ String settingUrl = mContext.getResources().getString(
+ R.string.config_networkCaptivePortalServerUrl);
+
+ if (!TextUtils.isEmpty(settingUrl)) {
+ return settingUrl;
+ }
+
+ settingUrl = Settings.Global.getString(mContext.getContentResolver(),
+ Settings.Global.CAPTIVE_PORTAL_HTTP_URL);
+ if (!TextUtils.isEmpty(settingUrl)) {
+ return settingUrl;
+ }
+
+ return DEFAULT_CAPTIVE_PORTAL_HTTP_URL;
}
@Override
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index d8bb635..1913635 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 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 @@
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<Integer, PrivateDnsConfig> mPrivateDnsMap;
@@ -243,10 +245,10 @@
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 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 @@
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 d7a57b9..35f7ea3 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 @@
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,
@@ -314,6 +315,7 @@
}
}
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);
@@ -456,8 +458,8 @@
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;
}
@@ -476,27 +478,30 @@
// 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.
- 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());
}
}
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index 262ba7a..66bd27c 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 @@
NetworkInfo.State.SUSPENDED,
};
+ private final IDnsResolver mDnsResolver;
private final INetd mNetd;
private final INetworkManagementService mNMService;
@@ -84,7 +86,9 @@
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 @@
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 @@
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 8f2825c..cfa9131 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.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 @@
// 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 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 @@
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 @@
mNetworkMonitor = networkMonitor;
}
+ /**
+ * Set the NetworkCapabilities on this NetworkAgentInfo. Also attempts to notify NetworkMonitor
+ * of the new capabilities, if NetworkMonitor has been created.
+ *
+ * <p>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/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index 0c55934..b694602 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -37,7 +37,6 @@
import android.content.pm.PackageManagerInternal;
import android.content.pm.UserInfo;
import android.net.INetd;
-import android.net.util.NetdService;
import android.os.Build;
import android.os.INetworkManagementService;
import android.os.RemoteException;
@@ -77,7 +76,8 @@
private final Context mContext;
private final PackageManager mPackageManager;
private final UserManager mUserManager;
- private final INetworkManagementService mNetd;
+ private final INetworkManagementService mNMS;
+ private final INetd mNetd;
// Values are User IDs.
private final Set<Integer> mUsers = new HashSet<>();
@@ -100,6 +100,9 @@
app.requestedPermissionsFlags);
}
}
+ } else {
+ // The last package of this uid is removed from device. Clean the package up.
+ permission = INetd.PERMISSION_UNINSTALLED;
}
return permission;
}
@@ -115,11 +118,12 @@
}
}
- public PermissionMonitor(Context context, INetworkManagementService netd) {
+ public PermissionMonitor(Context context, INetworkManagementService nms, INetd netdService) {
mContext = context;
mPackageManager = context.getPackageManager();
mUserManager = UserManager.get(context);
- mNetd = netd;
+ mNMS = nms;
+ mNetd = netdService;
}
// Intended to be called only once at startup, after the system is ready. Installs a broadcast
@@ -285,11 +289,11 @@
}
try {
if (add) {
- mNetd.setPermission("NETWORK", toIntArray(network));
- mNetd.setPermission("SYSTEM", toIntArray(system));
+ mNMS.setPermission("NETWORK", toIntArray(network));
+ mNMS.setPermission("SYSTEM", toIntArray(system));
} else {
- mNetd.clearPermission(toIntArray(network));
- mNetd.clearPermission(toIntArray(system));
+ mNMS.clearPermission(toIntArray(network));
+ mNMS.clearPermission(toIntArray(system));
}
} catch (RemoteException e) {
loge("Exception when updating permissions: " + e);
@@ -447,7 +451,8 @@
*
* @hide
*/
- private void sendPackagePermissionsForUid(int uid, int permissions) {
+ @VisibleForTesting
+ void sendPackagePermissionsForUid(int uid, int permissions) {
SparseIntArray netdPermissionsAppIds = new SparseIntArray();
netdPermissionsAppIds.put(uid, permissions);
sendPackagePermissionsToNetd(netdPermissionsAppIds);
@@ -462,15 +467,16 @@
*
* @hide
*/
- private void sendPackagePermissionsToNetd(SparseIntArray netdPermissionsAppIds) {
- INetd netdService = NetdService.getInstance();
- if (netdService == null) {
+ @VisibleForTesting
+ void sendPackagePermissionsToNetd(SparseIntArray netdPermissionsAppIds) {
+ if (mNetd == null) {
Log.e(TAG, "Failed to get the netd service");
return;
}
ArrayList<Integer> allPermissionAppIds = new ArrayList<>();
ArrayList<Integer> internetPermissionAppIds = new ArrayList<>();
ArrayList<Integer> updateStatsPermissionAppIds = new ArrayList<>();
+ ArrayList<Integer> noPermissionAppIds = new ArrayList<>();
ArrayList<Integer> uninstalledAppIds = new ArrayList<>();
for (int i = 0; i < netdPermissionsAppIds.size(); i++) {
int permissions = netdPermissionsAppIds.valueAt(i);
@@ -485,8 +491,10 @@
updateStatsPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
break;
case INetd.NO_PERMISSIONS:
- uninstalledAppIds.add(netdPermissionsAppIds.keyAt(i));
+ noPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
break;
+ case INetd.PERMISSION_UNINSTALLED:
+ uninstalledAppIds.add(netdPermissionsAppIds.keyAt(i));
default:
Log.e(TAG, "unknown permission type: " + permissions + "for uid: "
+ netdPermissionsAppIds.keyAt(i));
@@ -495,20 +503,24 @@
try {
// TODO: add a lock inside netd to protect IPC trafficSetNetPermForUids()
if (allPermissionAppIds.size() != 0) {
- netdService.trafficSetNetPermForUids(
+ mNetd.trafficSetNetPermForUids(
INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS,
ArrayUtils.convertToIntArray(allPermissionAppIds));
}
if (internetPermissionAppIds.size() != 0) {
- netdService.trafficSetNetPermForUids(INetd.PERMISSION_INTERNET,
+ mNetd.trafficSetNetPermForUids(INetd.PERMISSION_INTERNET,
ArrayUtils.convertToIntArray(internetPermissionAppIds));
}
if (updateStatsPermissionAppIds.size() != 0) {
- netdService.trafficSetNetPermForUids(INetd.PERMISSION_UPDATE_DEVICE_STATS,
+ mNetd.trafficSetNetPermForUids(INetd.PERMISSION_UPDATE_DEVICE_STATS,
ArrayUtils.convertToIntArray(updateStatsPermissionAppIds));
}
+ if (noPermissionAppIds.size() != 0) {
+ mNetd.trafficSetNetPermForUids(INetd.NO_PERMISSIONS,
+ ArrayUtils.convertToIntArray(noPermissionAppIds));
+ }
if (uninstalledAppIds.size() != 0) {
- netdService.trafficSetNetPermForUids(INetd.NO_PERMISSIONS,
+ mNetd.trafficSetNetPermForUids(INetd.PERMISSION_UNINSTALLED,
ArrayUtils.convertToIntArray(uninstalledAppIds));
}
} catch (RemoteException e) {
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
index c62d85e..9098f90 100644
--- a/tests/net/Android.bp
+++ b/tests/net/Android.bp
@@ -1,12 +1,10 @@
//########################################################################
// Build FrameworksNetTests package
//########################################################################
-
-android_test {
- name: "FrameworksNetTests",
- // Include all test java files.
- srcs: ["java/**/*.java"],
+java_defaults {
+ name: "FrameworksNetTests-jni-defaults",
static_libs: [
+ "FrameworksNetCommonTests",
"frameworks-base-testutils",
"framework-protos",
"androidx.test.rules",
@@ -20,6 +18,52 @@
"android.test.base",
"android.test.mock",
],
+ jni_libs: [
+ "ld-android",
+ "libartbase",
+ "libbacktrace",
+ "libbase",
+ "libbinder",
+ "libbinderthreadstate",
+ "libbpf",
+ "libbpf_android",
+ "libc++",
+ "libcgrouprc",
+ "libcrypto",
+ "libcutils",
+ "libdexfile",
+ "libdl_android",
+ "libhidl-gen-utils",
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libjsoncpp",
+ "liblog",
+ "liblzma",
+ "libnativehelper",
+ "libnetdbpf",
+ "libnetdutils",
+ "libpackagelistparser",
+ "libpcre2",
+ "libprocessgroup",
+ "libselinux",
+ "libui",
+ "libutils",
+ "libvndksupport",
+ "libtinyxml2",
+ "libunwindstack",
+ "libutilscallstack",
+ "libziparchive",
+ "libz",
+ "netd_aidl_interface-cpp",
+ "libnetworkstatsfactorytestjni",
+ ],
+}
+
+android_test {
+ name: "FrameworksNetTests",
+ defaults: ["FrameworksNetTests-jni-defaults"],
+ srcs: ["java/**/*.java"],
platform_apis: true,
test_suites: ["device-tests"],
certificate: "platform",
diff --git a/tests/net/common/Android.bp b/tests/net/common/Android.bp
new file mode 100644
index 0000000..0a1ac75
--- /dev/null
+++ b/tests/net/common/Android.bp
@@ -0,0 +1,29 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Tests in this folder are included both in unit tests and CTS.
+// They must be fast and stable, and exercise public or test APIs.
+java_library {
+ name: "FrameworksNetCommonTests",
+ srcs: ["java/**/*.java"],
+ static_libs: [
+ "androidx.test.rules",
+ "junit",
+ ],
+ libs: [
+ "android.test.base.stubs",
+ ],
+}
\ No newline at end of file
diff --git a/tests/net/java/android/net/IpPrefixTest.java b/tests/net/common/java/android/net/IpPrefixTest.java
similarity index 84%
rename from tests/net/java/android/net/IpPrefixTest.java
rename to tests/net/common/java/android/net/IpPrefixTest.java
index 3cc0e36..719960d 100644
--- a/tests/net/java/android/net/IpPrefixTest.java
+++ b/tests/net/common/java/android/net/IpPrefixTest.java
@@ -39,7 +39,7 @@
@SmallTest
public class IpPrefixTest {
- private static InetAddress Address(String addr) {
+ private static InetAddress address(String addr) {
return InetAddress.parseNumericAddress(addr);
}
@@ -58,59 +58,59 @@
try {
p = new IpPrefix((byte[]) null, 9);
fail("Expected NullPointerException: null byte array");
- } catch(RuntimeException expected) {}
+ } catch (RuntimeException expected) { }
try {
p = new IpPrefix((InetAddress) null, 10);
fail("Expected NullPointerException: null InetAddress");
- } catch(RuntimeException expected) {}
+ } catch (RuntimeException expected) { }
try {
p = new IpPrefix((String) null);
fail("Expected NullPointerException: null String");
- } catch(RuntimeException expected) {}
+ } catch (RuntimeException expected) { }
try {
byte[] b2 = {1, 2, 3, 4, 5};
p = new IpPrefix(b2, 29);
fail("Expected IllegalArgumentException: invalid array length");
- } catch(IllegalArgumentException expected) {}
+ } catch (IllegalArgumentException expected) { }
try {
p = new IpPrefix("1.2.3.4");
fail("Expected IllegalArgumentException: no prefix length");
- } catch(IllegalArgumentException expected) {}
+ } catch (IllegalArgumentException expected) { }
try {
p = new IpPrefix("1.2.3.4/");
fail("Expected IllegalArgumentException: empty prefix length");
- } catch(IllegalArgumentException expected) {}
+ } catch (IllegalArgumentException expected) { }
try {
p = new IpPrefix("foo/32");
fail("Expected IllegalArgumentException: invalid address");
- } catch(IllegalArgumentException expected) {}
+ } catch (IllegalArgumentException expected) { }
try {
p = new IpPrefix("1/32");
fail("Expected IllegalArgumentException: deprecated IPv4 format");
- } catch(IllegalArgumentException expected) {}
+ } catch (IllegalArgumentException expected) { }
try {
p = new IpPrefix("1.2.3.256/32");
fail("Expected IllegalArgumentException: invalid IPv4 address");
- } catch(IllegalArgumentException expected) {}
+ } catch (IllegalArgumentException expected) { }
try {
p = new IpPrefix("foo/32");
fail("Expected IllegalArgumentException: non-address");
- } catch(IllegalArgumentException expected) {}
+ } catch (IllegalArgumentException expected) { }
try {
p = new IpPrefix("f00:::/32");
fail("Expected IllegalArgumentException: invalid IPv6 address");
- } catch(IllegalArgumentException expected) {}
+ } catch (IllegalArgumentException expected) { }
}
@Test
@@ -132,17 +132,17 @@
try {
p = new IpPrefix(IPV4_BYTES, 33);
fail("Expected IllegalArgumentException: invalid prefix length");
- } catch(RuntimeException expected) {}
+ } catch (RuntimeException expected) { }
try {
p = new IpPrefix(IPV4_BYTES, 128);
fail("Expected IllegalArgumentException: invalid prefix length");
- } catch(RuntimeException expected) {}
+ } catch (RuntimeException expected) { }
try {
p = new IpPrefix(IPV4_BYTES, -1);
fail("Expected IllegalArgumentException: negative prefix length");
- } catch(RuntimeException expected) {}
+ } catch (RuntimeException expected) { }
p = new IpPrefix(IPV6_BYTES, 128);
assertEquals("2001:db8:dead:beef:f00::a0/128", p.toString());
@@ -162,12 +162,12 @@
try {
p = new IpPrefix(IPV6_BYTES, -1);
fail("Expected IllegalArgumentException: negative prefix length");
- } catch(RuntimeException expected) {}
+ } catch (RuntimeException expected) { }
try {
p = new IpPrefix(IPV6_BYTES, 129);
fail("Expected IllegalArgumentException: negative prefix length");
- } catch(RuntimeException expected) {}
+ } catch (RuntimeException expected) { }
}
@@ -226,29 +226,28 @@
@Test
public void testContainsInetAddress() {
IpPrefix p = new IpPrefix("2001:db8:f00::ace:d00d/127");
- assertTrue(p.contains(Address("2001:db8:f00::ace:d00c")));
- assertTrue(p.contains(Address("2001:db8:f00::ace:d00d")));
- 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")));
+ assertTrue(p.contains(address("2001:db8:f00::ace:d00c")));
+ assertTrue(p.contains(address("2001:db8:f00::ace:d00d")));
+ 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(address("8.8.8.8")));
p = new IpPrefix("192.0.2.0/23");
- assertTrue(p.contains(Address("192.0.2.43")));
- assertTrue(p.contains(Address("192.0.3.21")));
- assertFalse(p.contains(Address("192.0.0.21")));
- assertFalse(p.contains(Address("8.8.8.8")));
- assertFalse(p.contains(Address("2001:4868:4860::8888")));
+ assertTrue(p.contains(address("192.0.2.43")));
+ assertTrue(p.contains(address("192.0.3.21")));
+ assertFalse(p.contains(address("192.0.0.21")));
+ assertFalse(p.contains(address("8.8.8.8")));
+ assertFalse(p.contains(address("2001:4868:4860::8888")));
IpPrefix ipv6Default = new IpPrefix("::/0");
- assertTrue(ipv6Default.contains(Address("2001:db8::f00")));
- assertFalse(ipv6Default.contains(Address("192.0.2.1")));
+ assertTrue(ipv6Default.contains(address("2001:db8::f00")));
+ assertFalse(ipv6Default.contains(address("192.0.2.1")));
IpPrefix ipv4Default = new IpPrefix("0.0.0.0/0");
- assertTrue(ipv4Default.contains(Address("255.255.255.255")));
- assertTrue(ipv4Default.contains(Address("192.0.2.1")));
- assertFalse(ipv4Default.contains(Address("2001:db8::f00")));
+ assertTrue(ipv4Default.contains(address("255.255.255.255")));
+ assertTrue(ipv4Default.contains(address("192.0.2.1")));
+ assertFalse(ipv4Default.contains(address("2001:db8::f00")));
}
@Test
@@ -316,10 +315,10 @@
p = new IpPrefix(b, random.nextInt(129));
}
if (p.equals(oldP)) {
- assertEquals(p.hashCode(), oldP.hashCode());
+ assertEquals(p.hashCode(), oldP.hashCode());
}
if (p.hashCode() != oldP.hashCode()) {
- assertNotEquals(p, oldP);
+ assertNotEquals(p, oldP);
}
}
}
@@ -333,9 +332,9 @@
new IpPrefix("0.0.0.0/0"),
};
for (int i = 0; i < prefixes.length; i++) {
- for (int j = i + 1; j < prefixes.length; j++) {
- assertNotEquals(prefixes[i].hashCode(), prefixes[j].hashCode());
- }
+ for (int j = i + 1; j < prefixes.length; j++) {
+ assertNotEquals(prefixes[i].hashCode(), prefixes[j].hashCode());
+ }
}
}
@@ -372,8 +371,8 @@
}
public void assertParcelingIsLossless(IpPrefix p) {
- IpPrefix p2 = passThroughParcel(p);
- assertEquals(p, p2);
+ IpPrefix p2 = passThroughParcel(p);
+ assertEquals(p, p2);
}
@Test
diff --git a/tests/net/java/android/net/ipmemorystore/ParcelableTests.java b/tests/net/java/android/net/ipmemorystore/ParcelableTests.java
index 76cccc9..1a3ea60 100644
--- a/tests/net/java/android/net/ipmemorystore/ParcelableTests.java
+++ b/tests/net/java/android/net/ipmemorystore/ParcelableTests.java
@@ -44,6 +44,8 @@
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 @@
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 @@
// 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 6f48da3..c2fc0b3 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.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;
@@ -240,6 +241,7 @@
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;
@@ -256,6 +258,7 @@
@Mock INetworkManagementService mNetworkManagementService;
@Mock INetworkStatsService mStatsService;
@Mock INetworkPolicyManager mNpm;
+ @Mock IDnsResolver mMockDnsResolver;
@Mock INetd mMockNetd;
@Mock NetworkStackClient mNetworkStack;
@@ -496,7 +499,7 @@
};
try {
- doAnswer(validateAnswer).when(mNetworkMonitor).notifyNetworkConnected();
+ doAnswer(validateAnswer).when(mNetworkMonitor).notifyNetworkConnected(any(), any());
doAnswer(validateAnswer).when(mNetworkMonitor).forceReevaluation(anyInt());
} catch (RemoteException e) {
fail(e.getMessage());
@@ -1053,8 +1056,8 @@
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;
}
@@ -1218,7 +1221,8 @@
mStatsService,
mNpm,
mock(IpConnectivityLog.class),
- mMockNetd);
+ mMockNetd,
+ mMockDnsResolver);
final ArgumentCaptor<INetworkPolicyListener> policyListenerCaptor =
ArgumentCaptor.forClass(INetworkPolicyListener.class);
@@ -3043,6 +3047,47 @@
}
@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();
mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
@@ -4777,14 +4822,14 @@
ArgumentCaptor<String[]> 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);
@@ -4801,28 +4846,29 @@
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"}));
@@ -4830,7 +4876,7 @@
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";
@@ -4840,22 +4886,21 @@
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<String[]> 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");
@@ -4868,9 +4913,10 @@
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);
@@ -4889,9 +4935,9 @@
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"}));
@@ -4899,7 +4945,7 @@
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);
@@ -4911,26 +4957,26 @@
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");
@@ -5761,6 +5807,7 @@
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));
@@ -5768,7 +5815,7 @@
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);
@@ -5778,17 +5825,22 @@
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);
@@ -5818,6 +5870,12 @@
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);
@@ -5825,7 +5883,7 @@
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);
@@ -5840,7 +5898,9 @@
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 */,
@@ -5854,7 +5914,7 @@
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);
@@ -5937,6 +5997,7 @@
// 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
@@ -5944,8 +6005,9 @@
// 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/IpSecServiceRefcountedResourceTest.java b/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java
index 68ff777..22a2c94 100644
--- a/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java
@@ -18,6 +18,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.eq;
@@ -134,11 +135,11 @@
IBinder binderMock = mock(IBinder.class);
doThrow(new RemoteException()).when(binderMock).linkToDeath(anyObject(), anyInt());
- RefcountedResource<IResource> refcountedResource = getTestRefcountedResource(binderMock);
-
- // Verify that cleanup is performed (Spy limitations prevent verification of method calls
- // for binder death scenario; check refcount to determine if cleanup was performed.)
- assertEquals(-1, refcountedResource.mRefCount);
+ try {
+ getTestRefcountedResource(binderMock);
+ fail("Expected exception to propogate when binder fails to link to death");
+ } catch (RuntimeException expected) {
+ }
}
@Test
diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java
index b5c3e92..4a35015 100644
--- a/tests/net/java/com/android/server/IpSecServiceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceTest.java
@@ -156,10 +156,21 @@
@Test
public void testOpenAndCloseUdpEncapsulationSocket() throws Exception {
- int localport = findUnusedPort();
+ int localport = -1;
+ IpSecUdpEncapResponse udpEncapResp = null;
- IpSecUdpEncapResponse udpEncapResp =
- mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
+ for (int i = 0; i < IpSecService.MAX_PORT_BIND_ATTEMPTS; i++) {
+ localport = findUnusedPort();
+
+ udpEncapResp = mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
+ assertNotNull(udpEncapResp);
+ if (udpEncapResp.status == IpSecManager.Status.OK) {
+ break;
+ }
+
+ // Else retry to reduce possibility for port-bind failures.
+ }
+
assertNotNull(udpEncapResp);
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
assertEquals(localport, udpEncapResp.port);
@@ -204,12 +215,11 @@
@Test
public void testOpenUdpEncapsulationSocketAfterClose() throws Exception {
- int localport = findUnusedPort();
IpSecUdpEncapResponse udpEncapResp =
- mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
+ mIpSecService.openUdpEncapsulationSocket(0, new Binder());
assertNotNull(udpEncapResp);
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
- assertEquals(localport, udpEncapResp.port);
+ int localport = udpEncapResp.port;
mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
udpEncapResp.fileDescriptor.close();
@@ -226,12 +236,11 @@
*/
@Test
public void testUdpEncapPortNotReleased() throws Exception {
- int localport = findUnusedPort();
IpSecUdpEncapResponse udpEncapResp =
- mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
+ mIpSecService.openUdpEncapsulationSocket(0, new Binder());
assertNotNull(udpEncapResp);
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
- assertEquals(localport, udpEncapResp.port);
+ int localport = udpEncapResp.port;
udpEncapResp.fileDescriptor.close();
@@ -273,14 +282,11 @@
@Test
public void testOpenUdpEncapsulationSocketTwice() throws Exception {
- int localport = findUnusedPort();
-
IpSecUdpEncapResponse udpEncapResp =
- mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
+ mIpSecService.openUdpEncapsulationSocket(0, new Binder());
assertNotNull(udpEncapResp);
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
- assertEquals(localport, udpEncapResp.port);
- mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
+ int localport = udpEncapResp.port;
IpSecUdpEncapResponse testUdpEncapResp =
mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
diff --git a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
index 15ba43d..8fa0ab9 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.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 @@
MockContentResolver mContentResolver;
@Mock Context mCtx;
- @Mock INetworkManagementService mNMService;
+ @Mock IDnsResolver mMockDnsResolver;
@Mock MockableSystemProperties mSystemProperties;
@Before
@@ -83,7 +83,7 @@
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 6de4aa1..142769f 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.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 @@
LingerMonitor mMonitor;
@Mock ConnectivityService mConnService;
+ @Mock IDnsResolver mDnsResolver;
@Mock INetd mNetd;
@Mock INetworkManagementService mNMS;
@Mock Context mCtx;
@@ -353,7 +355,7 @@
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 cc09fb7..b709af1 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.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 @@
@Mock ConnectivityService mConnectivity;
@Mock NetworkMisc mMisc;
+ @Mock IDnsResolver mDnsResolver;
@Mock INetd mNetd;
@Mock INetworkManagementService mNms;
@Mock InterfaceConfiguration mConfig;
@@ -72,7 +74,7 @@
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 @@
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 @@
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 @@
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 @@
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/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index 354c08f..106cd1f 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -20,10 +20,13 @@
import static android.Manifest.permission.CHANGE_WIFI_STATE;
import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
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.ApplicationInfo.PRIVATE_FLAG_OEM;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRODUCT;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_VENDOR;
+import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.os.Process.SYSTEM_UID;
@@ -41,26 +44,35 @@
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageList;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.net.INetd;
import android.os.Build;
import android.os.INetworkManagementService;
import android.os.UserHandle;
+import android.util.SparseIntArray;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.LocalServices;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
+import java.util.ArrayList;
import java.util.HashMap;
@RunWith(AndroidJUnit4.class)
@@ -69,7 +81,11 @@
private static final int MOCK_USER1 = 0;
private static final int MOCK_USER2 = 1;
private static final int MOCK_UID1 = 10001;
+ private static final int MOCK_UID2 = 10086;
+ private static final int SYSTEM_UID1 = 1000;
+ private static final int SYSTEM_UID2 = 1008;
private static final String MOCK_PACKAGE1 = "appName1";
+ private static final String MOCK_PACKAGE2 = "appName2";
private static final String SYSTEM_PACKAGE1 = "sysName1";
private static final String SYSTEM_PACKAGE2 = "sysName2";
private static final String PARTITION_SYSTEM = "system";
@@ -82,14 +98,29 @@
@Mock private Context mContext;
@Mock private PackageManager mPackageManager;
@Mock private INetworkManagementService mNMS;
+ @Mock private INetd mNetdService;
+ @Mock private PackageManagerInternal mMockPmi;
+ private PackageManagerInternal.PackageListObserver mObserver;
private PermissionMonitor mPermissionMonitor;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
- mPermissionMonitor = spy(new PermissionMonitor(mContext, mNMS));
+ mPermissionMonitor = spy(new PermissionMonitor(mContext, mNMS, mNetdService));
+
+ LocalServices.removeServiceForTest(PackageManagerInternal.class);
+ LocalServices.addService(PackageManagerInternal.class, mMockPmi);
+ when(mMockPmi.getPackageList(any())).thenReturn(new PackageList(new ArrayList<String>(),
+ /* observer */ null));
+ when(mPackageManager.getInstalledPackages(anyInt())).thenReturn(/* empty app list */ null);
+ mPermissionMonitor.startMonitoring();
+
+ final ArgumentCaptor<PackageManagerInternal.PackageListObserver> observerCaptor =
+ ArgumentCaptor.forClass(PackageManagerInternal.PackageListObserver.class);
+ verify(mMockPmi).getPackageList(observerCaptor.capture());
+ mObserver = observerCaptor.getValue();
}
private boolean hasBgPermission(String partition, int targetSdkVersion, int uid,
@@ -104,9 +135,20 @@
}
private PackageInfo packageInfoWithPermissions(String[] permissions, String partition) {
+ int[] requestedPermissionsFlags = new int[permissions.length];
+ for (int i = 0; i < permissions.length; i++) {
+ requestedPermissionsFlags[i] = REQUESTED_PERMISSION_GRANTED;
+ }
+ return packageInfoWithPermissions(permissions, partition,
+ requestedPermissionsFlags);
+ }
+
+ private PackageInfo packageInfoWithPermissions(String[] permissions, String partition,
+ int[] requestedPermissionsFlags) {
final PackageInfo packageInfo = new PackageInfo();
packageInfo.requestedPermissions = permissions;
packageInfo.applicationInfo = new ApplicationInfo();
+ packageInfo.requestedPermissionsFlags = requestedPermissionsFlags;
int privateFlags = 0;
switch (partition) {
case PARTITION_OEM:
@@ -337,4 +379,164 @@
mPermissionMonitor.onPackageRemoved(UserHandle.getUid(user, uid));
}
}
+
+ private class NetdServiceMonitor {
+ private final HashMap<Integer, Integer> mPermissions = new HashMap<>();
+
+ NetdServiceMonitor(INetd mockNetdService) throws Exception {
+ // Add hook to verify and track result of setPermission.
+ doAnswer((InvocationOnMock invocation) -> {
+ final Object[] args = invocation.getArguments();
+ final int permission = (int) args[0];
+ for (final int uid : (int[]) args[1]) {
+ mPermissions.put(uid, permission);
+ }
+ return null;
+ }).when(mockNetdService).trafficSetNetPermForUids(anyInt(), any(int[].class));
+ }
+
+ public void expectPermission(int permission, int[] apps) {
+ for (final int app : apps) {
+ if (!mPermissions.containsKey(app)) {
+ fail("uid " + app + " does not exist.");
+ }
+ if (mPermissions.get(app) != permission) {
+ fail("uid " + app + " has wrong permission: " + mPermissions.get(app));
+ }
+ }
+ }
+ }
+
+ @Test
+ public void testPackagePermissionUpdate() throws Exception {
+ final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
+ // MOCK_UID1: MOCK_PACKAGE1 only has internet permission.
+ // MOCK_UID2: MOCK_PACKAGE2 does not have any permission.
+ // SYSTEM_UID1: SYSTEM_PACKAGE1 has internet permission and update device stats permission.
+ // SYSTEM_UID2: SYSTEM_PACKAGE2 has only update device stats permission.
+
+ SparseIntArray netdPermissionsAppIds = new SparseIntArray();
+ netdPermissionsAppIds.put(MOCK_UID1, INetd.PERMISSION_INTERNET);
+ netdPermissionsAppIds.put(MOCK_UID2, INetd.NO_PERMISSIONS);
+ netdPermissionsAppIds.put(SYSTEM_UID1, INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS);
+ netdPermissionsAppIds.put(SYSTEM_UID2, INetd.PERMISSION_UPDATE_DEVICE_STATS);
+
+ // Send the permission information to netd, expect permission updated.
+ mPermissionMonitor.sendPackagePermissionsToNetd(netdPermissionsAppIds);
+
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET,
+ new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(INetd.NO_PERMISSIONS, new int[]{MOCK_UID2});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{SYSTEM_UID1});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UPDATE_DEVICE_STATS,
+ new int[]{SYSTEM_UID2});
+
+ // Update permission of MOCK_UID1, expect new permission show up.
+ mPermissionMonitor.sendPackagePermissionsForUid(MOCK_UID1,
+ INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS);
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+
+ // Change permissions of SYSTEM_UID2, expect new permission show up and old permission
+ // revoked.
+ mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID2,
+ INetd.PERMISSION_INTERNET);
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{SYSTEM_UID2});
+
+ // Revoke permission from SYSTEM_UID1, expect no permission stored.
+ mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID1, INetd.NO_PERMISSIONS);
+ mNetdServiceMonitor.expectPermission(INetd.NO_PERMISSIONS, new int[]{SYSTEM_UID1});
+ }
+
+ private PackageInfo addPackage(String packageName, int uid, String[] permissions)
+ throws Exception {
+ PackageInfo packageInfo = packageInfoWithPermissions(permissions, PARTITION_SYSTEM);
+ when(mPackageManager.getPackageInfo(eq(packageName), anyInt())).thenReturn(packageInfo);
+ when(mPackageManager.getPackagesForUid(eq(uid))).thenReturn(new String[]{packageName});
+ mObserver.onPackageAdded(packageName, uid);
+ return packageInfo;
+ }
+
+ @Test
+ public void testPackageInstall() throws Exception {
+ final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
+
+ addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+
+ addPackage(MOCK_PACKAGE2, MOCK_UID2, new String[] {INTERNET});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID2});
+ }
+
+ @Test
+ public void testPackageInstallSharedUid() throws Exception {
+ final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
+
+ PackageInfo packageInfo1 = addPackage(MOCK_PACKAGE1, MOCK_UID1,
+ new String[] {INTERNET, UPDATE_DEVICE_STATS});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+
+ // Install another package with the same uid and no permissions should not cause the UID to
+ // lose permissions.
+ PackageInfo packageInfo2 = packageInfoWithPermissions(new String[]{}, PARTITION_SYSTEM);
+ when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2);
+ when(mPackageManager.getPackagesForUid(MOCK_UID1))
+ .thenReturn(new String[]{MOCK_PACKAGE1, MOCK_PACKAGE2});
+ mObserver.onPackageAdded(MOCK_PACKAGE2, MOCK_UID1);
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+ }
+
+ @Test
+ public void testPackageUninstallBasic() throws Exception {
+ final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
+
+ addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+
+ when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
+ mObserver.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
+ }
+
+ @Test
+ public void testPackageUpdate() throws Exception {
+ final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
+
+ addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+
+ // Remove and install the same package to simulate the update action
+ when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
+ mObserver.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
+
+ addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
+ }
+
+ @Test
+ public void testPackageUninstallWithMultiplePackages() throws Exception {
+ final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
+
+ addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+
+ // Mock another package with the same uid but different permissions.
+ PackageInfo packageInfo2 = packageInfoWithPermissions(new String[] {INTERNET},
+ PARTITION_SYSTEM);
+ when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2);
+ when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{
+ MOCK_PACKAGE2});
+
+ mObserver.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
+ }
}
diff --git a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java b/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java
similarity index 96%
rename from tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
rename to tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java
index 4ec4fdd..95bc7d9 100644
--- a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.net;
+package com.android.server.net;
import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
import static android.net.NetworkStats.METERED_NO;
@@ -70,6 +70,10 @@
IoUtils.deleteContents(mTestProc);
}
+ // The libandroid_servers which have the native method is not available to
+ // applications. So in order to have a test support native library, the native code
+ // related to networkStatsFactory is compiled to a minimal native library and loaded here.
+ System.loadLibrary("networkstatsfactorytestjni");
mFactory = new NetworkStatsFactory(mTestProc, false);
}
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 dc20185..fb84611 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 @@
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})),
diff --git a/tests/net/smoketest/Android.bp b/tests/net/smoketest/Android.bp
new file mode 100644
index 0000000..ef1ad2c
--- /dev/null
+++ b/tests/net/smoketest/Android.bp
@@ -0,0 +1,17 @@
+// This test exists only because the jni_libs list for these tests is difficult to
+// maintain: the test itself only depends on libnetworkstatsfactorytestjni, but the test
+// fails to load that library unless *all* the dependencies of that library are explicitly
+// listed in jni_libs. This means that whenever any of the dependencies changes the test
+// starts failing and breaking presubmits in frameworks/base. We cannot easily put
+// FrameworksNetTests into global presubmit because they are at times flaky, but this
+// test is effectively empty beyond validating that the libraries load correctly, and
+// thus should be stable enough to put in global presubmit.
+//
+// TODO: remove this hack when there is a better solution for jni_libs that includes
+// dependent libraries.
+android_test {
+ name: "FrameworksNetSmokeTests",
+ defaults: ["FrameworksNetTests-jni-defaults"],
+ srcs: ["java/SmokeTest.java"],
+ test_suites: ["device-tests"],
+}