Merge "avoid generating reserved local MACs"
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 0e10de8..111a8c4 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -655,7 +655,7 @@
* {@hide}
*/
@Deprecated
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
+ @UnsupportedAppUsage
public static final int TYPE_WIFI_P2P = 13;
/**
@@ -3449,14 +3449,19 @@
final NetworkCallback callback;
synchronized (sCallbacks) {
callback = sCallbacks.get(request);
+ if (callback == null) {
+ Log.w(TAG,
+ "callback not found for " + getCallbackName(message.what) + " message");
+ return;
+ }
+ if (message.what == CALLBACK_UNAVAIL) {
+ sCallbacks.remove(request);
+ callback.networkRequest = ALREADY_UNREGISTERED;
+ }
}
if (DBG) {
Log.d(TAG, getCallbackName(message.what) + " for network " + network);
}
- if (callback == null) {
- Log.w(TAG, "callback not found for " + getCallbackName(message.what) + " message");
- return;
- }
switch (message.what) {
case CALLBACK_PRECHECK: {
@@ -3608,8 +3613,9 @@
* @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
* the callback must not be shared - it uniquely specifies this request.
* The callback is invoked on the default internal Handler.
- * @throws IllegalArgumentException if {@code request} specifies any mutable
- * {@code NetworkCapabilities}.
+ * @throws IllegalArgumentException if {@code request} contains invalid network capabilities.
+ * @throws SecurityException if missing the appropriate permissions.
+ * @throws RuntimeException if request limit per UID is exceeded.
*/
public void requestNetwork(@NonNull NetworkRequest request,
@NonNull NetworkCallback networkCallback) {
@@ -3644,8 +3650,9 @@
* @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
* the callback must not be shared - it uniquely specifies this request.
* @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
- * @throws IllegalArgumentException if {@code request} specifies any mutable
- * {@code NetworkCapabilities}.
+ * @throws IllegalArgumentException if {@code request} contains invalid network capabilities.
+ * @throws SecurityException if missing the appropriate permissions.
+ * @throws RuntimeException if request limit per UID is exceeded.
*/
public void requestNetwork(@NonNull NetworkRequest request,
@NonNull NetworkCallback networkCallback, @NonNull Handler handler) {
@@ -3681,6 +3688,9 @@
* @param timeoutMs The time in milliseconds to attempt looking for a suitable network
* before {@link NetworkCallback#onUnavailable()} is called. The timeout must
* be a positive value (i.e. >0).
+ * @throws IllegalArgumentException if {@code request} contains invalid network capabilities.
+ * @throws SecurityException if missing the appropriate permissions.
+ * @throws RuntimeException if request limit per UID is exceeded.
*/
public void requestNetwork(@NonNull NetworkRequest request,
@NonNull NetworkCallback networkCallback, int timeoutMs) {
@@ -3715,6 +3725,9 @@
* @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
* @param timeoutMs The time in milliseconds to attempt looking for a suitable network
* before {@link NetworkCallback#onUnavailable} is called.
+ * @throws IllegalArgumentException if {@code request} contains invalid network capabilities.
+ * @throws SecurityException if missing the appropriate permissions.
+ * @throws RuntimeException if request limit per UID is exceeded.
*/
public void requestNetwork(@NonNull NetworkRequest request,
@NonNull NetworkCallback networkCallback, @NonNull Handler handler, int timeoutMs) {
@@ -3785,9 +3798,9 @@
* @param operation Action to perform when the network is available (corresponds
* to the {@link NetworkCallback#onAvailable} call. Typically
* comes from {@link PendingIntent#getBroadcast}. Cannot be null.
- * @throws IllegalArgumentException if {@code request} contains either
- * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} or
- * {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}.
+ * @throws IllegalArgumentException if {@code request} contains invalid network capabilities.
+ * @throws SecurityException if missing the appropriate permissions.
+ * @throws RuntimeException if request limit per UID is exceeded.
*/
public void requestNetwork(@NonNull NetworkRequest request,
@NonNull PendingIntent operation) {
@@ -3995,8 +4008,10 @@
synchronized (sCallbacks) {
Preconditions.checkArgument(networkCallback.networkRequest != null,
"NetworkCallback was not registered");
- Preconditions.checkArgument(networkCallback.networkRequest != ALREADY_UNREGISTERED,
- "NetworkCallback was already unregistered");
+ if (networkCallback.networkRequest == ALREADY_UNREGISTERED) {
+ Log.d(TAG, "NetworkCallback was already unregistered");
+ return;
+ }
for (Map.Entry<NetworkRequest, NetworkCallback> e : sCallbacks.entrySet()) {
if (e.getValue() == networkCallback) {
reqs.add(e.getKey());
diff --git a/core/java/android/net/DnsResolver.java b/core/java/android/net/DnsResolver.java
index 68826cb..0b1a845 100644
--- a/core/java/android/net/DnsResolver.java
+++ b/core/java/android/net/DnsResolver.java
@@ -16,16 +16,17 @@
package android.net;
+import static android.net.NetworkUtils.getDnsNetwork;
import static android.net.NetworkUtils.resNetworkCancel;
import static android.net.NetworkUtils.resNetworkQuery;
import static android.net.NetworkUtils.resNetworkResult;
import static android.net.NetworkUtils.resNetworkSend;
+import static android.net.util.DnsUtils.haveIpv4;
+import static android.net.util.DnsUtils.haveIpv6;
+import static android.net.util.DnsUtils.rfc6724Sort;
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 static android.system.OsConstants.ENONET;
import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
@@ -33,19 +34,14 @@
import android.annotation.Nullable;
import android.os.CancellationSignal;
import android.os.Looper;
+import android.os.MessageQueue;
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;
@@ -196,8 +192,8 @@
final Object lock = new Object();
final FileDescriptor queryfd;
try {
- queryfd = resNetworkSend((network != null
- ? network.getNetIdForResolv() : NETID_UNSET), query, query.length, flags);
+ queryfd = resNetworkSend((network != null)
+ ? network.getNetIdForResolv() : NETID_UNSET, query, query.length, flags);
} catch (ErrnoException e) {
executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
return;
@@ -237,8 +233,8 @@
final Object lock = new Object();
final FileDescriptor queryfd;
try {
- queryfd = resNetworkQuery((network != null
- ? network.getNetIdForResolv() : NETID_UNSET), domain, nsClass, nsType, flags);
+ queryfd = resNetworkQuery((network != null)
+ ? network.getNetIdForResolv() : NETID_UNSET, domain, nsClass, nsType, flags);
} catch (ErrnoException e) {
executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
return;
@@ -252,14 +248,16 @@
private class InetAddressAnswerAccumulator implements Callback<byte[]> {
private final List<InetAddress> mAllAnswers;
+ private final Network mNetwork;
private int mRcode;
private DnsException mDnsException;
private final Callback<? super List<InetAddress>> mUserCallback;
private final int mTargetAnswerCount;
private int mReceivedAnswerCount = 0;
- InetAddressAnswerAccumulator(int size,
+ InetAddressAnswerAccumulator(@NonNull Network network, int size,
@NonNull Callback<? super List<InetAddress>> callback) {
+ mNetwork = network;
mTargetAnswerCount = size;
mAllAnswers = new ArrayList<>();
mUserCallback = callback;
@@ -280,8 +278,7 @@
private void maybeReportAnswer() {
if (++mReceivedAnswerCount != mTargetAnswerCount) return;
if (mAllAnswers.isEmpty() && maybeReportError()) return;
- // TODO: Do RFC6724 sort.
- mUserCallback.onAnswer(mAllAnswers, mRcode);
+ mUserCallback.onAnswer(rfc6724Sort(mNetwork, mAllAnswers), mRcode);
}
@Override
@@ -308,7 +305,7 @@
/**
* Send a DNS query with the specified name on a network with both IPv4 and IPv6,
- * get back a set of InetAddresses asynchronously.
+ * get back a set of InetAddresses with rfc6724 sorting style asynchronously.
*
* This method will examine the connection ability on given network, and query IPv4
* and IPv6 if connection is available.
@@ -335,8 +332,23 @@
return;
}
final Object lock = new Object();
- final boolean queryIpv6 = haveIpv6(network);
- final boolean queryIpv4 = haveIpv4(network);
+ final Network queryNetwork;
+ try {
+ queryNetwork = (network != null) ? network : getDnsNetwork();
+ } catch (ErrnoException e) {
+ executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
+ return;
+ }
+ final boolean queryIpv6 = haveIpv6(queryNetwork);
+ final boolean queryIpv4 = haveIpv4(queryNetwork);
+
+ // This can only happen if queryIpv4 and queryIpv6 are both false.
+ // This almost certainly means that queryNetwork does not exist or no longer exists.
+ if (!queryIpv6 && !queryIpv4) {
+ executor.execute(() -> callback.onError(
+ new DnsException(ERROR_SYSTEM, new ErrnoException("resNetworkQuery", ENONET))));
+ return;
+ }
final FileDescriptor v4fd;
final FileDescriptor v6fd;
@@ -345,9 +357,8 @@
if (queryIpv6) {
try {
- v6fd = resNetworkQuery((network != null
- ? network.getNetIdForResolv() : NETID_UNSET),
- domain, CLASS_IN, TYPE_AAAA, flags);
+ v6fd = resNetworkQuery(queryNetwork.getNetIdForResolv(), domain, CLASS_IN,
+ TYPE_AAAA, flags);
} catch (ErrnoException e) {
executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
return;
@@ -355,7 +366,6 @@
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);
@@ -365,9 +375,8 @@
if (queryIpv4) {
try {
- v4fd = resNetworkQuery((network != null
- ? network.getNetIdForResolv() : NETID_UNSET),
- domain, CLASS_IN, TYPE_A, flags);
+ v4fd = resNetworkQuery(queryNetwork.getNetIdForResolv(), domain, CLASS_IN, TYPE_A,
+ flags);
} catch (ErrnoException e) {
if (queryIpv6) resNetworkCancel(v6fd); // Closes fd, marks it invalid.
executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
@@ -377,7 +386,7 @@
} else v4fd = null;
final InetAddressAnswerAccumulator accumulator =
- new InetAddressAnswerAccumulator(queryCount, callback);
+ new InetAddressAnswerAccumulator(queryNetwork, queryCount, callback);
synchronized (lock) {
if (queryIpv6) {
@@ -398,7 +407,7 @@
/**
* Send a DNS query with the specified name and query type, get back a set of
- * InetAddresses asynchronously.
+ * InetAddresses with rfc6724 sorting style asynchronously.
*
* The answer will be provided asynchronously through the provided {@link Callback}.
*
@@ -423,15 +432,17 @@
}
final Object lock = new Object();
final FileDescriptor queryfd;
+ final Network queryNetwork;
try {
- queryfd = resNetworkQuery((network != null
- ? network.getNetIdForResolv() : NETID_UNSET), domain, CLASS_IN, nsType, flags);
+ queryNetwork = (network != null) ? network : getDnsNetwork();
+ queryfd = resNetworkQuery(queryNetwork.getNetIdForResolv(), domain, CLASS_IN, nsType,
+ flags);
} catch (ErrnoException e) {
executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
return;
}
final InetAddressAnswerAccumulator accumulator =
- new InetAddressAnswerAccumulator(1, callback);
+ new InetAddressAnswerAccumulator(queryNetwork, 1, callback);
synchronized (lock) {
registerFDListener(executor, queryfd, accumulator, cancellationSignal, lock);
if (cancellationSignal == null) return;
@@ -456,10 +467,20 @@
private void registerFDListener(@NonNull Executor executor,
@NonNull FileDescriptor queryfd, @NonNull Callback<? super byte[]> answerCallback,
@Nullable CancellationSignal cancellationSignal, @NonNull Object lock) {
- Looper.getMainLooper().getQueue().addOnFileDescriptorEventListener(
+ final MessageQueue mainThreadMessageQueue = Looper.getMainLooper().getQueue();
+ mainThreadMessageQueue.addOnFileDescriptorEventListener(
queryfd,
FD_EVENTS,
(fd, events) -> {
+ // b/134310704
+ // Unregister fd event listener before resNetworkResult is called to prevent
+ // race condition caused by fd reused.
+ // For example when querying v4 and v6, it's possible that the first query ends
+ // and the fd is closed before the second request starts, which might return
+ // the same fd for the second request. By that time, the looper must have
+ // unregistered the fd, otherwise another event listener can't be registered.
+ mainThreadMessageQueue.removeOnFileDescriptorEventListener(fd);
+
executor.execute(() -> {
DnsResponse resp = null;
ErrnoException exception = null;
@@ -480,7 +501,11 @@
}
answerCallback.onAnswer(resp.answerbuf, resp.rcode);
});
- // Unregister this fd listener
+
+ // The file descriptor has already been unregistered, so it does not really
+ // matter what is returned here. In spirit 0 (meaning "unregister this FD")
+ // is still the closest to what the looper needs to do. When returning 0,
+ // Looper knows to ignore the fd if it has already been unregistered.
return 0;
});
}
@@ -500,38 +525,6 @@
});
}
- // 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/NattKeepalivePacketData.java b/core/java/android/net/NattKeepalivePacketData.java
index bdb246f..a77c244 100644
--- a/core/java/android/net/NattKeepalivePacketData.java
+++ b/core/java/android/net/NattKeepalivePacketData.java
@@ -21,6 +21,8 @@
import android.net.SocketKeepalive.InvalidPacketException;
import android.net.util.IpUtils;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.system.OsConstants;
import java.net.Inet4Address;
@@ -29,8 +31,7 @@
import java.nio.ByteOrder;
/** @hide */
-public final class NattKeepalivePacketData extends KeepalivePacketData {
-
+public final class NattKeepalivePacketData extends KeepalivePacketData implements Parcelable {
// This should only be constructed via static factory methods, such as
// nattKeepalivePacket
private NattKeepalivePacketData(InetAddress srcAddress, int srcPort,
@@ -77,4 +78,41 @@
return new NattKeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, buf.array());
}
+
+ /** Parcelable Implementation */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Write to parcel */
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(srcAddress.getHostAddress());
+ out.writeString(dstAddress.getHostAddress());
+ out.writeInt(srcPort);
+ out.writeInt(dstPort);
+ }
+
+ /** Parcelable Creator */
+ public static final Parcelable.Creator<NattKeepalivePacketData> CREATOR =
+ new Parcelable.Creator<NattKeepalivePacketData>() {
+ public NattKeepalivePacketData createFromParcel(Parcel in) {
+ final InetAddress srcAddress =
+ InetAddresses.parseNumericAddress(in.readString());
+ final InetAddress dstAddress =
+ InetAddresses.parseNumericAddress(in.readString());
+ final int srcPort = in.readInt();
+ final int dstPort = in.readInt();
+ try {
+ return NattKeepalivePacketData.nattKeepalivePacket(srcAddress, srcPort,
+ dstAddress, dstPort);
+ } catch (InvalidPacketException e) {
+ throw new IllegalArgumentException(
+ "Invalid NAT-T keepalive data: " + e.error);
+ }
+ }
+
+ public NattKeepalivePacketData[] newArray(int size) {
+ return new NattKeepalivePacketData[size];
+ }
+ };
}
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 1edea55..b3f829a 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -178,7 +178,21 @@
*/
public static final int EVENT_SOCKET_KEEPALIVE = BASE + 13;
- // TODO: move the above 2 constants down so they are in order once merge conflicts are resolved
+ /**
+ * Sent by ConnectivityService to inform this network transport of signal strength thresholds
+ * that when crossed should trigger a system wakeup and a NetworkCapabilities update.
+ *
+ * obj = int[] describing signal strength thresholds.
+ */
+ public static final int CMD_SET_SIGNAL_STRENGTH_THRESHOLDS = BASE + 14;
+
+ /**
+ * Sent by ConnectivityService to the NeworkAgent to inform the agent to avoid
+ * automatically reconnecting to this network (e.g. via autojoin). Happens
+ * when user selects "No" option on the "Stay connected?" dialog box.
+ */
+ public static final int CMD_PREVENT_AUTOMATIC_RECONNECT = BASE + 15;
+
/**
* Sent by the KeepaliveTracker to NetworkAgent to add a packet filter.
*
@@ -198,21 +212,6 @@
*/
public static final int CMD_REMOVE_KEEPALIVE_PACKET_FILTER = BASE + 17;
- /**
- * Sent by ConnectivityService to inform this network transport of signal strength thresholds
- * that when crossed should trigger a system wakeup and a NetworkCapabilities update.
- *
- * obj = int[] describing signal strength thresholds.
- */
- public static final int CMD_SET_SIGNAL_STRENGTH_THRESHOLDS = BASE + 14;
-
- /**
- * Sent by ConnectivityService to the NeworkAgent to inform the agent to avoid
- * automatically reconnecting to this network (e.g. via autojoin). Happens
- * when user selects "No" option on the "Stay connected?" dialog box.
- */
- public static final int CMD_PREVENT_AUTOMATIC_RECONNECT = BASE + 15;
-
// TODO : remove these two constructors. They are a stopgap measure to help sheperding a number
// of dependent changes that would conflict throughout the automerger graph. Having these
// temporarily helps with the process of going through with all these dependent changes across
@@ -434,7 +433,32 @@
* {@link #saveAcceptUnvalidated} to respect the user's choice.
*/
public void explicitlySelected(boolean acceptUnvalidated) {
- queueOrSendMessage(EVENT_SET_EXPLICITLY_SELECTED, acceptUnvalidated ? 1 : 0, 0);
+ explicitlySelected(true /* explicitlySelected */, acceptUnvalidated);
+ }
+
+ /**
+ * Called by the bearer to indicate whether the network was manually selected by the user.
+ * This should be called before the NetworkInfo is marked CONNECTED so that this
+ * Network can be given special treatment at that time.
+ *
+ * If {@code explicitlySelected} is {@code true}, and {@code acceptUnvalidated} is {@code true},
+ * then the system will switch to this network. If {@code explicitlySelected} is {@code true}
+ * and {@code acceptUnvalidated} is {@code false}, and the network cannot be validated, the
+ * system will ask the user whether to switch to this network. If the user confirms and selects
+ * "don't ask again", then the system will call {@link #saveAcceptUnvalidated} to persist the
+ * user's choice. Thus, if the transport ever calls this method with {@code explicitlySelected}
+ * set to {@code true} and {@code acceptUnvalidated} set to {@code false}, it must also
+ * implement {@link #saveAcceptUnvalidated} to respect the user's choice.
+ *
+ * If {@code explicitlySelected} is {@code false} and {@code acceptUnvalidated} is
+ * {@code true}, the system will interpret this as the user having accepted partial connectivity
+ * on this network. Thus, the system will switch to the network and consider it validated even
+ * if it only provides partial connectivity, but the network is not otherwise treated specially.
+ */
+ public void explicitlySelected(boolean explicitlySelected, boolean acceptUnvalidated) {
+ queueOrSendMessage(EVENT_SET_EXPLICITLY_SELECTED,
+ explicitlySelected ? 1 : 0,
+ acceptUnvalidated ? 1 : 0);
}
/**
@@ -511,7 +535,6 @@
* override this method.
*/
protected void addKeepalivePacketFilter(Message msg) {
- onSocketKeepaliveEvent(msg.arg1, SocketKeepalive.ERROR_UNSUPPORTED);
}
/**
@@ -520,7 +543,6 @@
* must override this method.
*/
protected void removeKeepalivePacketFilter(Message msg) {
- onSocketKeepaliveEvent(msg.arg1, SocketKeepalive.ERROR_UNSUPPORTED);
}
/**
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index d07ff13..228e62d 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -152,6 +152,12 @@
public static native void resNetworkCancel(FileDescriptor fd);
/**
+ * DNS resolver series jni method.
+ * Attempts to get network which resolver will use if no network is explicitly selected.
+ */
+ public static native Network getDnsNetwork() throws ErrnoException;
+
+ /**
* 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/SocketKeepalive.java b/core/java/android/net/SocketKeepalive.java
index 9d91620..ec73866 100644
--- a/core/java/android/net/SocketKeepalive.java
+++ b/core/java/android/net/SocketKeepalive.java
@@ -43,6 +43,12 @@
* To stop an existing keepalive, call {@link SocketKeepalive#stop}. The system will call
* {@link SocketKeepalive.Callback#onStopped} if the operation was successful or
* {@link SocketKeepalive.Callback#onError} if an error occurred.
+ *
+ * For cellular, the device MUST support at least 1 keepalive slot.
+ *
+ * For WiFi, the device SHOULD support keepalive offload. If it does not, it MUST reply with
+ * {@link SocketKeepalive.Callback#onError} with {@code ERROR_UNSUPPORTED} to any keepalive offload
+ * request. If it does, it MUST support at least 3 concurrent keepalive slots.
*/
public abstract class SocketKeepalive implements AutoCloseable {
static final String TAG = "SocketKeepalive";
diff --git a/core/java/android/net/StaticIpConfiguration.java b/core/java/android/net/StaticIpConfiguration.java
index f01e213..0600036 100644
--- a/core/java/android/net/StaticIpConfiguration.java
+++ b/core/java/android/net/StaticIpConfiguration.java
@@ -22,7 +22,6 @@
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.net.shared.InetAddressUtils;
-import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -54,19 +53,19 @@
@TestApi
public final class StaticIpConfiguration implements Parcelable {
/** @hide */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+ @UnsupportedAppUsage
@Nullable
public LinkAddress ipAddress;
/** @hide */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+ @UnsupportedAppUsage
@Nullable
public InetAddress gateway;
/** @hide */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+ @UnsupportedAppUsage
@NonNull
public final ArrayList<InetAddress> dnsServers;
/** @hide */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+ @UnsupportedAppUsage
@Nullable
public String domains;
diff --git a/core/java/android/net/TestNetworkManager.java b/core/java/android/net/TestNetworkManager.java
index e274005..4ac4a69 100644
--- a/core/java/android/net/TestNetworkManager.java
+++ b/core/java/android/net/TestNetworkManager.java
@@ -56,6 +56,26 @@
/**
* Sets up a capability-limited, testing-only network for a given interface
*
+ * @param lp The LinkProperties for the TestNetworkService to use for this test network. Note
+ * that the interface name and link addresses will be overwritten, and the passed-in values
+ * discarded.
+ * @param isMetered Whether or not the network should be considered metered.
+ * @param binder A binder object guarding the lifecycle of this test network.
+ * @hide
+ */
+ public void setupTestNetwork(
+ @NonNull LinkProperties lp, boolean isMetered, @NonNull IBinder binder) {
+ Preconditions.checkNotNull(lp, "Invalid LinkProperties");
+ try {
+ mService.setupTestNetwork(lp.getInterfaceName(), lp, isMetered, binder);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Sets up a capability-limited, testing-only network for a given interface
+ *
* @param iface the name of the interface to be used for the Network LinkProperties.
* @param binder A binder object guarding the lifecycle of this test network.
* @hide
@@ -63,7 +83,7 @@
@TestApi
public void setupTestNetwork(@NonNull String iface, @NonNull IBinder binder) {
try {
- mService.setupTestNetwork(iface, binder);
+ mService.setupTestNetwork(iface, null, true, binder);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/net/util/DnsUtils.java b/core/java/android/net/util/DnsUtils.java
new file mode 100644
index 0000000..7908353
--- /dev/null
+++ b/core/java/android/net/util/DnsUtils.java
@@ -0,0 +1,379 @@
+/*
+ * 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.
+ */
+
+package android.net.util;
+
+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.NonNull;
+import android.annotation.Nullable;
+import android.net.InetAddresses;
+import android.net.Network;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.util.Log;
+
+import com.android.internal.util.BitUtils;
+
+import libcore.io.IoUtils;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * @hide
+ */
+public class DnsUtils {
+ private static final String TAG = "DnsUtils";
+ private static final int CHAR_BIT = 8;
+ public static final int IPV6_ADDR_SCOPE_NODELOCAL = 0x01;
+ public static final int IPV6_ADDR_SCOPE_LINKLOCAL = 0x02;
+ public static final int IPV6_ADDR_SCOPE_SITELOCAL = 0x05;
+ public static final int IPV6_ADDR_SCOPE_GLOBAL = 0x0e;
+ private static final Comparator<SortableAddress> sRfc6724Comparator = new Rfc6724Comparator();
+
+ /**
+ * Comparator to sort SortableAddress in Rfc6724 style.
+ */
+ public static class Rfc6724Comparator implements Comparator<SortableAddress> {
+ // This function matches the behaviour of _rfc6724_compare in the native resolver.
+ @Override
+ public int compare(SortableAddress span1, SortableAddress span2) {
+ // Rule 1: Avoid unusable destinations.
+ if (span1.hasSrcAddr != span2.hasSrcAddr) {
+ return span2.hasSrcAddr - span1.hasSrcAddr;
+ }
+
+ // Rule 2: Prefer matching scope.
+ if (span1.scopeMatch != span2.scopeMatch) {
+ return span2.scopeMatch - span1.scopeMatch;
+ }
+
+ // TODO: Implement rule 3: Avoid deprecated addresses.
+ // TODO: Implement rule 4: Prefer home addresses.
+
+ // Rule 5: Prefer matching label.
+ if (span1.labelMatch != span2.labelMatch) {
+ return span2.labelMatch - span1.labelMatch;
+ }
+
+ // Rule 6: Prefer higher precedence.
+ if (span1.precedence != span2.precedence) {
+ return span2.precedence - span1.precedence;
+ }
+
+ // TODO: Implement rule 7: Prefer native transport.
+
+ // Rule 8: Prefer smaller scope.
+ if (span1.scope != span2.scope) {
+ return span1.scope - span2.scope;
+ }
+
+ // Rule 9: Use longest matching prefix. IPv6 only.
+ if (span1.prefixMatchLen != span2.prefixMatchLen) {
+ return span2.prefixMatchLen - span1.prefixMatchLen;
+ }
+
+ // Rule 10: Leave the order unchanged. Collections.sort is a stable sort.
+ return 0;
+ }
+ }
+
+ /**
+ * Class used to sort with RFC 6724
+ */
+ public static class SortableAddress {
+ public final int label;
+ public final int labelMatch;
+ public final int scope;
+ public final int scopeMatch;
+ public final int precedence;
+ public final int prefixMatchLen;
+ public final int hasSrcAddr;
+ public final InetAddress address;
+
+ public SortableAddress(@NonNull InetAddress addr, @Nullable InetAddress srcAddr) {
+ address = addr;
+ hasSrcAddr = (srcAddr != null) ? 1 : 0;
+ label = findLabel(addr);
+ scope = findScope(addr);
+ precedence = findPrecedence(addr);
+ labelMatch = ((srcAddr != null) && (label == findLabel(srcAddr))) ? 1 : 0;
+ scopeMatch = ((srcAddr != null) && (scope == findScope(srcAddr))) ? 1 : 0;
+ if (isIpv6Address(addr) && isIpv6Address(srcAddr)) {
+ prefixMatchLen = compareIpv6PrefixMatchLen(srcAddr, addr);
+ } else {
+ prefixMatchLen = 0;
+ }
+ }
+ }
+
+ /**
+ * Sort the given address list in RFC6724 order.
+ * Will leave the list unchanged if an error occurs.
+ *
+ * This function matches the behaviour of _rfc6724_sort in the native resolver.
+ */
+ public static @NonNull List<InetAddress> rfc6724Sort(@Nullable Network network,
+ @NonNull List<InetAddress> answers) {
+ final ArrayList<SortableAddress> sortableAnswerList = new ArrayList<>();
+ for (InetAddress addr : answers) {
+ sortableAnswerList.add(new SortableAddress(addr, findSrcAddress(network, addr)));
+ }
+
+ Collections.sort(sortableAnswerList, sRfc6724Comparator);
+
+ final List<InetAddress> sortedAnswers = new ArrayList<>();
+ for (SortableAddress ans : sortableAnswerList) {
+ sortedAnswers.add(ans.address);
+ }
+
+ return sortedAnswers;
+ }
+
+ private static @Nullable InetAddress findSrcAddress(@Nullable Network network,
+ @NonNull InetAddress addr) {
+ final int domain;
+ if (isIpv4Address(addr)) {
+ domain = AF_INET;
+ } else if (isIpv6Address(addr)) {
+ domain = AF_INET6;
+ } else {
+ return null;
+ }
+ final FileDescriptor socket;
+ try {
+ socket = Os.socket(domain, SOCK_DGRAM, IPPROTO_UDP);
+ } catch (ErrnoException e) {
+ Log.e(TAG, "findSrcAddress:" + e.toString());
+ return null;
+ }
+ try {
+ if (network != null) network.bindSocket(socket);
+ Os.connect(socket, new InetSocketAddress(addr, 0));
+ return ((InetSocketAddress) Os.getsockname(socket)).getAddress();
+ } catch (IOException | ErrnoException e) {
+ return null;
+ } finally {
+ IoUtils.closeQuietly(socket);
+ }
+ }
+
+ /**
+ * Get the label for a given IPv4/IPv6 address.
+ * RFC 6724, section 2.1.
+ *
+ * Note that Java will return an IPv4-mapped address as an IPv4 address.
+ */
+ private static int findLabel(@NonNull InetAddress addr) {
+ if (isIpv4Address(addr)) {
+ return 4;
+ } else if (isIpv6Address(addr)) {
+ if (addr.isLoopbackAddress()) {
+ return 0;
+ } else if (isIpv6Address6To4(addr)) {
+ return 2;
+ } else if (isIpv6AddressTeredo(addr)) {
+ return 5;
+ } else if (isIpv6AddressULA(addr)) {
+ return 13;
+ } else if (((Inet6Address) addr).isIPv4CompatibleAddress()) {
+ return 3;
+ } else if (addr.isSiteLocalAddress()) {
+ return 11;
+ } else if (isIpv6Address6Bone(addr)) {
+ return 12;
+ } else {
+ // All other IPv6 addresses, including global unicast addresses.
+ return 1;
+ }
+ } else {
+ // This should never happen.
+ return 1;
+ }
+ }
+
+ private static boolean isIpv6Address(@Nullable InetAddress addr) {
+ return addr instanceof Inet6Address;
+ }
+
+ private static boolean isIpv4Address(@Nullable InetAddress addr) {
+ return addr instanceof Inet4Address;
+ }
+
+ private static boolean isIpv6Address6To4(@NonNull InetAddress addr) {
+ if (!isIpv6Address(addr)) return false;
+ final byte[] byteAddr = addr.getAddress();
+ return byteAddr[0] == 0x20 && byteAddr[1] == 0x02;
+ }
+
+ private static boolean isIpv6AddressTeredo(@NonNull InetAddress addr) {
+ if (!isIpv6Address(addr)) return false;
+ final byte[] byteAddr = addr.getAddress();
+ return byteAddr[0] == 0x20 && byteAddr[1] == 0x01 && byteAddr[2] == 0x00
+ && byteAddr[3] == 0x00;
+ }
+
+ private static boolean isIpv6AddressULA(@NonNull InetAddress addr) {
+ return isIpv6Address(addr) && (addr.getAddress()[0] & 0xfe) == 0xfc;
+ }
+
+ private static boolean isIpv6Address6Bone(@NonNull InetAddress addr) {
+ if (!isIpv6Address(addr)) return false;
+ final byte[] byteAddr = addr.getAddress();
+ return byteAddr[0] == 0x3f && byteAddr[1] == (byte) 0xfe;
+ }
+
+ private static int getIpv6MulticastScope(@NonNull InetAddress addr) {
+ return !isIpv6Address(addr) ? 0 : (addr.getAddress()[1] & 0x0f);
+ }
+
+ private static int findScope(@NonNull InetAddress addr) {
+ if (isIpv6Address(addr)) {
+ if (addr.isMulticastAddress()) {
+ return getIpv6MulticastScope(addr);
+ } else if (addr.isLoopbackAddress() || addr.isLinkLocalAddress()) {
+ /**
+ * RFC 4291 section 2.5.3 says loopback is to be treated as having
+ * link-local scope.
+ */
+ return IPV6_ADDR_SCOPE_LINKLOCAL;
+ } else if (addr.isSiteLocalAddress()) {
+ return IPV6_ADDR_SCOPE_SITELOCAL;
+ } else {
+ return IPV6_ADDR_SCOPE_GLOBAL;
+ }
+ } else if (isIpv4Address(addr)) {
+ if (addr.isLoopbackAddress() || addr.isLinkLocalAddress()) {
+ return IPV6_ADDR_SCOPE_LINKLOCAL;
+ } else {
+ /**
+ * RFC 6724 section 3.2. Other IPv4 addresses, including private addresses
+ * and shared addresses (100.64.0.0/10), are assigned global scope.
+ */
+ return IPV6_ADDR_SCOPE_GLOBAL;
+ }
+ } else {
+ /**
+ * This should never happen.
+ * Return a scope with low priority as a last resort.
+ */
+ return IPV6_ADDR_SCOPE_NODELOCAL;
+ }
+ }
+
+ /**
+ * Get the precedence for a given IPv4/IPv6 address.
+ * RFC 6724, section 2.1.
+ *
+ * Note that Java will return an IPv4-mapped address as an IPv4 address.
+ */
+ private static int findPrecedence(@NonNull InetAddress addr) {
+ if (isIpv4Address(addr)) {
+ return 35;
+ } else if (isIpv6Address(addr)) {
+ if (addr.isLoopbackAddress()) {
+ return 50;
+ } else if (isIpv6Address6To4(addr)) {
+ return 30;
+ } else if (isIpv6AddressTeredo(addr)) {
+ return 5;
+ } else if (isIpv6AddressULA(addr)) {
+ return 3;
+ } else if (((Inet6Address) addr).isIPv4CompatibleAddress() || addr.isSiteLocalAddress()
+ || isIpv6Address6Bone(addr)) {
+ return 1;
+ } else {
+ // All other IPv6 addresses, including global unicast addresses.
+ return 40;
+ }
+ } else {
+ return 1;
+ }
+ }
+
+ /**
+ * Find number of matching initial bits between the two addresses.
+ */
+ private static int compareIpv6PrefixMatchLen(@NonNull InetAddress srcAddr,
+ @NonNull InetAddress dstAddr) {
+ final byte[] srcByte = srcAddr.getAddress();
+ final byte[] dstByte = dstAddr.getAddress();
+
+ // This should never happen.
+ if (srcByte.length != dstByte.length) return 0;
+
+ for (int i = 0; i < dstByte.length; ++i) {
+ if (srcByte[i] == dstByte[i]) {
+ continue;
+ }
+ int x = BitUtils.uint8(srcByte[i]) ^ BitUtils.uint8(dstByte[i]);
+ return i * CHAR_BIT + (Integer.numberOfLeadingZeros(x) - 24); // Java ints are 32 bits
+ }
+ return dstByte.length * CHAR_BIT;
+ }
+
+ /**
+ * Check if given network has Ipv4 capability
+ * This function matches the behaviour of have_ipv4 in the native resolver.
+ */
+ public static boolean haveIpv4(@Nullable Network network) {
+ final SocketAddress addrIpv4 =
+ new InetSocketAddress(InetAddresses.parseNumericAddress("8.8.8.8"), 0);
+ return checkConnectivity(network, AF_INET, addrIpv4);
+ }
+
+ /**
+ * Check if given network has Ipv6 capability
+ * This function matches the behaviour of have_ipv6 in the native resolver.
+ */
+ public static boolean haveIpv6(@Nullable Network network) {
+ final SocketAddress addrIpv6 =
+ new InetSocketAddress(InetAddresses.parseNumericAddress("2000::"), 0);
+ return checkConnectivity(network, AF_INET6, addrIpv6);
+ }
+
+ private static 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;
+ }
+}
diff --git a/core/java/android/net/util/KeepaliveUtils.java b/core/java/android/net/util/KeepaliveUtils.java
new file mode 100644
index 0000000..bfc4563
--- /dev/null
+++ b/core/java/android/net/util/KeepaliveUtils.java
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+
+package android.net.util;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.res.Resources;
+import android.net.NetworkCapabilities;
+import android.text.TextUtils;
+import android.util.AndroidRuntimeException;
+
+import com.android.internal.R;
+
+/**
+ * Collection of utilities for socket keepalive offload.
+ *
+ * @hide
+ */
+public final class KeepaliveUtils {
+
+ public static final String TAG = "KeepaliveUtils";
+
+ public static class KeepaliveDeviceConfigurationException extends AndroidRuntimeException {
+ public KeepaliveDeviceConfigurationException(final String msg) {
+ super(msg);
+ }
+ }
+
+ /**
+ * Read supported keepalive count for each transport type from overlay resource. This should be
+ * used to create a local variable store of resource customization, and use it as the input for
+ * {@link getSupportedKeepalivesForNetworkCapabilities}.
+ *
+ * @param context The context to read resource from.
+ * @return An array of supported keepalive count for each transport type.
+ */
+ @NonNull
+ public static int[] getSupportedKeepalives(@NonNull Context context) {
+ String[] res = null;
+ try {
+ res = context.getResources().getStringArray(
+ R.array.config_networkSupportedKeepaliveCount);
+ } catch (Resources.NotFoundException unused) {
+ }
+ if (res == null) throw new KeepaliveDeviceConfigurationException("invalid resource");
+
+ final int[] ret = new int[NetworkCapabilities.MAX_TRANSPORT + 1];
+ for (final String row : res) {
+ if (TextUtils.isEmpty(row)) {
+ throw new KeepaliveDeviceConfigurationException("Empty string");
+ }
+ final String[] arr = row.split(",");
+ if (arr.length != 2) {
+ throw new KeepaliveDeviceConfigurationException("Invalid parameter length");
+ }
+
+ int transport;
+ int supported;
+ try {
+ transport = Integer.parseInt(arr[0]);
+ supported = Integer.parseInt(arr[1]);
+ } catch (NumberFormatException e) {
+ throw new KeepaliveDeviceConfigurationException("Invalid number format");
+ }
+
+ if (!NetworkCapabilities.isValidTransport(transport)) {
+ throw new KeepaliveDeviceConfigurationException("Invalid transport " + transport);
+ }
+
+ if (supported < 0) {
+ throw new KeepaliveDeviceConfigurationException(
+ "Invalid supported count " + supported + " for "
+ + NetworkCapabilities.transportNameOf(transport));
+ }
+ ret[transport] = supported;
+ }
+ return ret;
+ }
+
+ /**
+ * Get supported keepalive count for the given {@link NetworkCapabilities}.
+ *
+ * @param supportedKeepalives An array of supported keepalive count for each transport type.
+ * @param nc The {@link NetworkCapabilities} of the network the socket keepalive is on.
+ *
+ * @return Supported keepalive count for the given {@link NetworkCapabilities}.
+ */
+ public static int getSupportedKeepalivesForNetworkCapabilities(
+ @NonNull int[] supportedKeepalives, @NonNull NetworkCapabilities nc) {
+ final int[] transports = nc.getTransportTypes();
+ if (transports.length == 0) return 0;
+ int supportedCount = supportedKeepalives[transports[0]];
+ // Iterate through transports and return minimum supported value.
+ for (final int transport : transports) {
+ if (supportedCount > supportedKeepalives[transport]) {
+ supportedCount = supportedKeepalives[transport];
+ }
+ }
+ return supportedCount;
+ }
+}
diff --git a/core/java/android/net/util/MultinetworkPolicyTracker.java b/core/java/android/net/util/MultinetworkPolicyTracker.java
index 30c5cd9..f7e494d 100644
--- a/core/java/android/net/util/MultinetworkPolicyTracker.java
+++ b/core/java/android/net/util/MultinetworkPolicyTracker.java
@@ -16,29 +16,32 @@
package android.net.util;
+import static android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI;
+import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
+
+import android.annotation.NonNull;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.Resources;
import android.database.ContentObserver;
-import android.net.ConnectivityManager;
import android.net.Uri;
import android.os.Handler;
-import android.os.Message;
import android.os.UserHandle;
import android.provider.Settings;
+import android.telephony.PhoneStateListener;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
import android.util.Slog;
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.util.Arrays;
import java.util.List;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.R;
-
-import static android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI;
-import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
-
/**
* A class to encapsulate management of the "Smart Networking" capability of
* avoiding bad Wi-Fi when, for example upstream connectivity is lost or
@@ -69,6 +72,7 @@
private volatile boolean mAvoidBadWifi = true;
private volatile int mMeteredMultipathPreference;
+ private int mActiveSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
public MultinetworkPolicyTracker(Context ctx, Handler handler) {
this(ctx, handler, null);
@@ -95,6 +99,14 @@
}
};
+ TelephonyManager.from(ctx).listen(new PhoneStateListener() {
+ @Override
+ public void onActiveDataSubscriptionIdChanged(int subId) {
+ mActiveSubId = subId;
+ reevaluate();
+ }
+ }, PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
+
updateAvoidBadWifi();
updateMeteredMultipathPreference();
}
@@ -131,7 +143,12 @@
* Whether the device or carrier configuration disables avoiding bad wifi by default.
*/
public boolean configRestrictsAvoidBadWifi() {
- return (mContext.getResources().getInteger(R.integer.config_networkAvoidBadWifi) == 0);
+ return (getResourcesForActiveSubId().getInteger(R.integer.config_networkAvoidBadWifi) == 0);
+ }
+
+ @NonNull
+ private Resources getResourcesForActiveSubId() {
+ return SubscriptionManager.getResourcesForSubId(mContext, mActiveSubId);
}
/**
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 28c59db..08aa1d9 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -18,26 +18,27 @@
#include <vector>
-#include "jni.h"
-#include <nativehelper/JNIHelp.h>
-#include <nativehelper/ScopedLocalRef.h>
-#include "NetdClient.h"
-#include <utils/misc.h>
-#include <android_runtime/AndroidRuntime.h>
-#include <utils/Log.h>
#include <arpa/inet.h>
-#include <net/if.h>
#include <linux/filter.h>
#include <linux/if_arp.h>
#include <linux/tcp.h>
+#include <net/if.h>
#include <netinet/ether.h>
#include <netinet/icmp6.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <netinet/udp.h>
-#include <cutils/properties.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <cutils/properties.h>
+#include <utils/misc.h>
+#include <utils/Log.h>
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedLocalRef.h>
+
+#include "NetdClient.h"
#include "core_jni_helpers.h"
+#include "jni.h"
extern "C" {
int ifc_enable(const char *ifname);
@@ -49,8 +50,8 @@
namespace android {
constexpr int MAXPACKETSIZE = 8 * 1024;
-// FrameworkListener limits the size of commands to 1024 bytes. TODO: fix this.
-constexpr int MAXCMDSIZE = 1024;
+// FrameworkListener limits the size of commands to 4096 bytes.
+constexpr int MAXCMDSIZE = 4096;
static void throwErrnoException(JNIEnv* env, const char* functionName, int error) {
ScopedLocalRef<jstring> detailMessage(env, env->NewStringUTF(functionName));
@@ -303,6 +304,21 @@
jniSetFileDescriptorOfFD(env, javaFd, -1);
}
+static jobject android_net_utils_getDnsNetwork(JNIEnv *env, jobject thiz) {
+ unsigned dnsNetId = 0;
+ if (int res = getNetworkForDns(&dnsNetId) < 0) {
+ throwErrnoException(env, "getDnsNetId", -res);
+ return nullptr;
+ }
+ bool privateDnsBypass = dnsNetId & NETID_USE_LOCAL_NAMESERVERS;
+
+ static jclass class_Network = MakeGlobalRefOrDie(
+ env, FindClassOrDie(env, "android/net/Network"));
+ static jmethodID ctor = env->GetMethodID(class_Network, "<init>", "(IZ)V");
+ return env->NewObject(
+ class_Network, ctor, dnsNetId & ~NETID_USE_LOCAL_NAMESERVERS, privateDnsBypass);
+}
+
static jobject android_net_utils_getTcpRepairWindow(JNIEnv *env, jobject thiz, jobject javaFd) {
if (javaFd == NULL) {
jniThrowNullPointerException(env, NULL);
@@ -359,6 +375,7 @@
{ "resNetworkQuery", "(ILjava/lang/String;III)Ljava/io/FileDescriptor;", (void*) android_net_utils_resNetworkQuery },
{ "resNetworkResult", "(Ljava/io/FileDescriptor;)Landroid/net/DnsResolver$DnsResponse;", (void*) android_net_utils_resNetworkResult },
{ "resNetworkCancel", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_resNetworkCancel },
+ { "getDnsNetwork", "()Landroid/net/Network;", (void*) android_net_utils_getDnsNetwork },
};
int register_android_net_NetworkUtils(JNIEnv* env)
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index c1aff75..667445b 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -25,8 +25,8 @@
import static android.net.ConnectivityManager.TYPE_VPN;
import static android.net.ConnectivityManager.getNetworkTypeName;
import static android.net.ConnectivityManager.isNetworkTypeValid;
-import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY;
-import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_VALID;
+import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL;
+import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
@@ -40,7 +40,7 @@
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkPolicyManager.RULE_NONE;
import static android.net.NetworkPolicyManager.uidRulesToString;
-import static android.net.shared.NetworkMonitorUtils.isValidationRequired;
+import static android.net.shared.NetworkMonitorUtils.isPrivateDnsValidationRequired;
import static android.os.Process.INVALID_UID;
import static android.system.OsConstants.IPPROTO_TCP;
import static android.system.OsConstants.IPPROTO_UDP;
@@ -77,6 +77,7 @@
import android.net.ISocketKeepaliveCallback;
import android.net.ITetheringEventCallback;
import android.net.InetAddresses;
+import android.net.IpMemoryStore;
import android.net.IpPrefix;
import android.net.LinkProperties;
import android.net.LinkProperties.CompareResult;
@@ -90,6 +91,7 @@
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkMisc;
+import android.net.NetworkMonitorManager;
import android.net.NetworkPolicyManager;
import android.net.NetworkQuotaInfo;
import android.net.NetworkRequest;
@@ -147,7 +149,6 @@
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.util.Xml;
@@ -165,9 +166,9 @@
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.MessageUtils;
-import com.android.internal.util.WakeupMessage;
import com.android.internal.util.XmlUtils;
import com.android.server.am.BatteryStatsService;
+import com.android.server.connectivity.AutodestructReference;
import com.android.server.connectivity.DataConnectionStats;
import com.android.server.connectivity.DnsManager;
import com.android.server.connectivity.DnsManager.PrivateDnsValidationUpdate;
@@ -301,7 +302,8 @@
/** Flag indicating if background data is restricted. */
private boolean mRestrictBackground;
- final private Context mContext;
+ private final Context mContext;
+ private final Dependencies mDeps;
// 0 is full bad, 100 is full good
private int mDefaultInetConditionPublished = 0;
@@ -582,11 +584,6 @@
private NetworkNotificationManager mNotifier;
private LingerMonitor mLingerMonitor;
- // sequence number for Networks; keep in sync with system/netd/NetworkController.cpp
- private static final int MIN_NET_ID = 100; // some reserved marks
- private static final int MAX_NET_ID = 65535 - 0x0400; // Top 1024 bits reserved by IpSecService
- private int mNextNetId = MIN_NET_ID;
-
// sequence number of NetworkRequests
private int mNextNetworkRequestId = 1;
@@ -634,7 +631,8 @@
* the first network for a given type changes, or if the default network
* changes.
*/
- private class LegacyTypeTracker {
+ @VisibleForTesting
+ static class LegacyTypeTracker {
private static final boolean DBG = true;
private static final boolean VDBG = false;
@@ -660,10 +658,12 @@
* - dump is thread-safe with respect to concurrent add and remove calls.
*/
private final ArrayList<NetworkAgentInfo> mTypeLists[];
+ @NonNull
+ private final ConnectivityService mService;
- public LegacyTypeTracker() {
- mTypeLists = (ArrayList<NetworkAgentInfo>[])
- new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE + 1];
+ LegacyTypeTracker(@NonNull ConnectivityService service) {
+ mService = service;
+ mTypeLists = new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE + 1];
}
public void addSupportedType(int type) {
@@ -712,10 +712,10 @@
}
// Send a broadcast if this is the first network of its type or if it's the default.
- final boolean isDefaultNetwork = isDefaultNetwork(nai);
+ final boolean isDefaultNetwork = mService.isDefaultNetwork(nai);
if ((list.size() == 1) || isDefaultNetwork) {
maybeLogBroadcast(nai, DetailedState.CONNECTED, type, isDefaultNetwork);
- sendLegacyNetworkBroadcast(nai, DetailedState.CONNECTED, type);
+ mService.sendLegacyNetworkBroadcast(nai, DetailedState.CONNECTED, type);
}
}
@@ -733,19 +733,18 @@
}
}
- final DetailedState state = DetailedState.DISCONNECTED;
-
if (wasFirstNetwork || wasDefault) {
- maybeLogBroadcast(nai, state, type, wasDefault);
- sendLegacyNetworkBroadcast(nai, state, type);
+ maybeLogBroadcast(nai, DetailedState.DISCONNECTED, type, wasDefault);
+ mService.sendLegacyNetworkBroadcast(nai, DetailedState.DISCONNECTED, type);
}
if (!list.isEmpty() && wasFirstNetwork) {
if (DBG) log("Other network available for type " + type +
", sending connected broadcast");
final NetworkAgentInfo replacement = list.get(0);
- maybeLogBroadcast(replacement, state, type, isDefaultNetwork(replacement));
- sendLegacyNetworkBroadcast(replacement, state, type);
+ maybeLogBroadcast(replacement, DetailedState.CONNECTED, type,
+ mService.isDefaultNetwork(replacement));
+ mService.sendLegacyNetworkBroadcast(replacement, DetailedState.CONNECTED, type);
}
}
@@ -760,7 +759,7 @@
// send out another legacy broadcast - currently only used for suspend/unsuspend
// toggle
public void update(NetworkAgentInfo nai) {
- final boolean isDefault = isDefaultNetwork(nai);
+ final boolean isDefault = mService.isDefaultNetwork(nai);
final DetailedState state = nai.networkInfo.getDetailedState();
for (int type = 0; type < mTypeLists.length; type++) {
final ArrayList<NetworkAgentInfo> list = mTypeLists[type];
@@ -768,7 +767,7 @@
final boolean isFirst = contains && (nai == list.get(0));
if (isFirst || contains && isDefault) {
maybeLogBroadcast(nai, state, type, isDefault);
- sendLegacyNetworkBroadcast(nai, state, type);
+ mService.sendLegacyNetworkBroadcast(nai, state, type);
}
}
}
@@ -804,7 +803,7 @@
pw.println();
}
}
- private LegacyTypeTracker mLegacyTypeTracker = new LegacyTypeTracker();
+ private final LegacyTypeTracker mLegacyTypeTracker = new LegacyTypeTracker(this);
/**
* Helper class which parses out priority arguments and dumps sections according to their
@@ -828,19 +827,113 @@
}
};
+ /**
+ * Dependencies of ConnectivityService, for injection in tests.
+ */
+ @VisibleForTesting
+ public static class Dependencies {
+ /**
+ * Get system properties to use in ConnectivityService.
+ */
+ public MockableSystemProperties getSystemProperties() {
+ return new MockableSystemProperties();
+ }
+
+ /**
+ * Create a HandlerThread to use in ConnectivityService.
+ */
+ public HandlerThread makeHandlerThread() {
+ return new HandlerThread("ConnectivityServiceThread");
+ }
+
+ /**
+ * Get a reference to the NetworkStackClient.
+ */
+ public NetworkStackClient getNetworkStack() {
+ return NetworkStackClient.getInstance();
+ }
+
+ /**
+ * @see Tethering
+ */
+ public Tethering makeTethering(@NonNull Context context,
+ @NonNull INetworkManagementService nms,
+ @NonNull INetworkStatsService statsService,
+ @NonNull INetworkPolicyManager policyManager,
+ @NonNull TetheringDependencies tetheringDeps) {
+ return new Tethering(context, nms, statsService, policyManager,
+ IoThread.get().getLooper(), getSystemProperties(), tetheringDeps);
+ }
+
+ /**
+ * @see ProxyTracker
+ */
+ public ProxyTracker makeProxyTracker(@NonNull Context context,
+ @NonNull Handler connServiceHandler) {
+ return new ProxyTracker(context, connServiceHandler, EVENT_PROXY_HAS_CHANGED);
+ }
+
+ /**
+ * @see NetIdManager
+ */
+ public NetIdManager makeNetIdManager() {
+ return new NetIdManager();
+ }
+
+ /**
+ * @see NetworkUtils#queryUserAccess(int, int)
+ */
+ public boolean queryUserAccess(int uid, int netId) {
+ return NetworkUtils.queryUserAccess(uid, netId);
+ }
+
+ /**
+ * @see MultinetworkPolicyTracker
+ */
+ public MultinetworkPolicyTracker makeMultinetworkPolicyTracker(
+ @NonNull Context c, @NonNull Handler h, @NonNull Runnable r) {
+ return new MultinetworkPolicyTracker(c, h, r);
+ }
+
+ /**
+ * @see ServiceManager#checkService(String)
+ */
+ public boolean hasService(@NonNull String name) {
+ return ServiceManager.checkService(name) != null;
+ }
+
+ /**
+ * @see IpConnectivityMetrics.Logger
+ */
+ public IpConnectivityMetrics.Logger getMetricsLogger() {
+ return checkNotNull(LocalServices.getService(IpConnectivityMetrics.Logger.class),
+ "no IpConnectivityMetrics service");
+ }
+
+ /**
+ * @see IpConnectivityMetrics
+ */
+ public IIpConnectivityMetrics getIpConnectivityMetrics() {
+ return IIpConnectivityMetrics.Stub.asInterface(
+ ServiceManager.getService(IpConnectivityLog.SERVICE_NAME));
+ }
+ }
+
public ConnectivityService(Context context, INetworkManagementService netManager,
INetworkStatsService statsService, INetworkPolicyManager policyManager) {
- this(context, netManager, statsService, policyManager,
- getDnsResolver(), new IpConnectivityLog(), NetdService.getInstance());
+ this(context, netManager, statsService, policyManager, getDnsResolver(),
+ new IpConnectivityLog(), NetdService.getInstance(), new Dependencies());
}
@VisibleForTesting
protected ConnectivityService(Context context, INetworkManagementService netManager,
INetworkStatsService statsService, INetworkPolicyManager policyManager,
- IDnsResolver dnsresolver, IpConnectivityLog logger, INetd netd) {
+ IDnsResolver dnsresolver, IpConnectivityLog logger, INetd netd, Dependencies deps) {
if (DBG) log("ConnectivityService starting up");
- mSystemProperties = getSystemProperties();
+ mDeps = checkNotNull(deps, "missing Dependencies");
+ mSystemProperties = mDeps.getSystemProperties();
+ mNetIdManager = mDeps.makeNetIdManager();
mMetricsLog = logger;
mDefaultRequest = createDefaultInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST);
@@ -857,7 +950,7 @@
mDefaultWifiRequest = createDefaultInternetRequestForTransport(
NetworkCapabilities.TRANSPORT_WIFI, NetworkRequest.Type.BACKGROUND_REQUEST);
- mHandlerThread = new HandlerThread("ConnectivityServiceThread");
+ mHandlerThread = mDeps.makeHandlerThread();
mHandlerThread.start();
mHandler = new InternalHandler(mHandlerThread.getLooper());
mTrackerHandler = new NetworkStateTrackerHandler(mHandlerThread.getLooper());
@@ -875,7 +968,7 @@
LocalServices.getService(NetworkPolicyManagerInternal.class),
"missing NetworkPolicyManagerInternal");
mDnsResolver = checkNotNull(dnsresolver, "missing IDnsResolver");
- mProxyTracker = makeProxyTracker();
+ mProxyTracker = mDeps.makeProxyTracker(mContext, mHandler);
mNetd = netd;
mKeyStore = KeyStore.getInstance();
@@ -943,7 +1036,7 @@
// Do the same for Ethernet, since it's often not specified in the configs, although many
// devices can use it via USB host adapters.
- if (mNetConfigs[TYPE_ETHERNET] == null && hasService(Context.ETHERNET_SERVICE)) {
+ if (mNetConfigs[TYPE_ETHERNET] == null && mDeps.hasService(Context.ETHERNET_SERVICE)) {
mLegacyTypeTracker.addSupportedType(TYPE_ETHERNET);
mNetworksDefined++;
}
@@ -961,7 +1054,10 @@
}
}
- mTethering = makeTethering();
+ mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+
+ mTethering = deps.makeTethering(mContext, mNMS, mStatsService, mPolicyManager,
+ makeTetheringDependencies());
mPermissionMonitor = new PermissionMonitor(mContext, mNetd);
@@ -1008,8 +1104,6 @@
final DataConnectionStats dataConnectionStats = new DataConnectionStats(mContext);
dataConnectionStats.startMonitoring();
- mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
-
mKeepaliveTracker = new KeepaliveTracker(mContext, mHandler);
mNotifier = new NetworkNotificationManager(mContext, mTelephonyManager,
mContext.getSystemService(NotificationManager.class));
@@ -1022,7 +1116,7 @@
LingerMonitor.DEFAULT_NOTIFICATION_RATE_LIMIT_MILLIS);
mLingerMonitor = new LingerMonitor(mContext, mNotifier, dailyLimit, rateLimit);
- mMultinetworkPolicyTracker = createMultinetworkPolicyTracker(
+ mMultinetworkPolicyTracker = mDeps.makeMultinetworkPolicyTracker(
mContext, mHandler, () -> rematchForAvoidBadWifiUpdate());
mMultinetworkPolicyTracker.start();
@@ -1032,10 +1126,8 @@
registerPrivateDnsSettingsCallbacks();
}
- @VisibleForTesting
- protected Tethering makeTethering() {
- // TODO: Move other elements into @Overridden getters.
- final TetheringDependencies deps = new TetheringDependencies() {
+ private TetheringDependencies makeTetheringDependencies() {
+ return new TetheringDependencies() {
@Override
public boolean isTetheringSupported() {
return ConnectivityService.this.isTetheringSupported();
@@ -1045,14 +1137,6 @@
return mDefaultRequest;
}
};
- return new Tethering(mContext, mNMS, mStatsService, mPolicyManager,
- IoThread.get().getLooper(), new MockableSystemProperties(),
- deps);
- }
-
- @VisibleForTesting
- protected ProxyTracker makeProxyTracker() {
- return new ProxyTracker(mContext, mHandler, EVENT_PROXY_HAS_CHANGED);
}
private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) {
@@ -1144,22 +1228,6 @@
return mNextNetworkRequestId++;
}
- @VisibleForTesting
- protected int reserveNetId() {
- synchronized (mNetworkForNetId) {
- for (int i = MIN_NET_ID; i <= MAX_NET_ID; i++) {
- int netId = mNextNetId;
- if (++mNextNetId > MAX_NET_ID) mNextNetId = MIN_NET_ID;
- // Make sure NetID unused. http://b/16815182
- if (!mNetIdInUse.get(netId)) {
- mNetIdInUse.put(netId, true);
- return netId;
- }
- }
- }
- throw new IllegalStateException("No free netIds");
- }
-
private NetworkState getFilteredNetworkState(int networkType, int uid) {
if (mLegacyTypeTracker.isTypeSupported(networkType)) {
final NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
@@ -1780,8 +1848,7 @@
// callback from each caller type. Need to re-factor NetdEventListenerService to allow
// multiple NetworkMonitor registrants.
if (nai != null && nai.satisfies(mDefaultRequest)) {
- Binder.withCleanCallingIdentity(() ->
- nai.networkMonitor().notifyDnsResponse(returnCode));
+ nai.networkMonitor().notifyDnsResponse(returnCode);
}
}
@@ -1792,11 +1859,8 @@
}
};
- @VisibleForTesting
- protected void registerNetdEventCallback() {
- final IIpConnectivityMetrics ipConnectivityMetrics =
- IIpConnectivityMetrics.Stub.asInterface(
- ServiceManager.getService(IpConnectivityLog.SERVICE_NAME));
+ private void registerNetdEventCallback() {
+ final IIpConnectivityMetrics ipConnectivityMetrics = mDeps.getIpConnectivityMetrics();
if (ipConnectivityMetrics == null) {
Slog.wtf(TAG, "Missing IIpConnectivityMetrics");
return;
@@ -2232,12 +2296,6 @@
protected static final String DEFAULT_TCP_BUFFER_SIZES = "4096,87380,110208,4096,16384,110208";
private static final String DEFAULT_TCP_RWND_KEY = "net.tcp.default_init_rwnd";
- // Overridden for testing purposes to avoid writing to SystemProperties.
- @VisibleForTesting
- protected MockableSystemProperties getSystemProperties() {
- return new MockableSystemProperties();
- }
-
private void updateTcpBufferSizes(String tcpBufferSizes) {
String[] values = null;
if (tcpBufferSizes != null) {
@@ -2571,11 +2629,11 @@
break;
}
case NetworkAgent.EVENT_SET_EXPLICITLY_SELECTED: {
- if (nai.everConnected && !nai.networkMisc.explicitlySelected) {
- loge("ERROR: already-connected network explicitly selected.");
+ if (nai.everConnected) {
+ loge("ERROR: cannot call explicitlySelected on already-connected network");
}
- nai.networkMisc.explicitlySelected = true;
- nai.networkMisc.acceptUnvalidated = msg.arg1 == 1;
+ nai.networkMisc.explicitlySelected = toBool(msg.arg1);
+ nai.networkMisc.acceptUnvalidated = toBool(msg.arg1) && toBool(msg.arg2);
// Mark the network as temporarily accepting partial connectivity so that it
// will be validated (and possibly become default) even if it only provides
// partial internet access. Note that if user connects to partial connectivity
@@ -2583,7 +2641,7 @@
// out of wifi coverage) and if the same wifi is available again, the device
// will auto connect to this wifi even though the wifi has "no internet".
// TODO: Evaluate using a separate setting in IpMemoryStore.
- nai.networkMisc.acceptPartialConnectivity = msg.arg1 == 1;
+ nai.networkMisc.acceptPartialConnectivity = toBool(msg.arg2);
break;
}
case NetworkAgent.EVENT_SOCKET_KEEPALIVE: {
@@ -2601,26 +2659,19 @@
final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(msg.arg2);
if (nai == null) break;
- final boolean partialConnectivity =
- (msg.arg1 == NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY)
- || (nai.networkMisc.acceptPartialConnectivity
- && nai.partialConnectivity);
- // Once a network is determined to have partial connectivity, it cannot
- // go back to full connectivity without a disconnect. This is because
- // NetworkMonitor can only communicate either PARTIAL_CONNECTIVITY or VALID,
- // but not both.
- // TODO: Provide multi-testResult to improve the communication between
- // ConnectivityService and NetworkMonitor, so that ConnectivityService could
- // know the real status of network.
+ final boolean wasPartial = nai.partialConnectivity;
+ nai.partialConnectivity = ((msg.arg1 & NETWORK_VALIDATION_RESULT_PARTIAL) != 0);
final boolean partialConnectivityChanged =
- (partialConnectivity && !nai.partialConnectivity);
+ (wasPartial != nai.partialConnectivity);
- final boolean valid = (msg.arg1 == NETWORK_TEST_RESULT_VALID);
+ final boolean valid = ((msg.arg1 & NETWORK_VALIDATION_RESULT_VALID) != 0);
final boolean wasValidated = nai.lastValidated;
final boolean wasDefault = isDefaultNetwork(nai);
- if (nai.everCaptivePortalDetected && !nai.captivePortalLoginNotified
- && valid) {
- nai.captivePortalLoginNotified = true;
+ // Only show a connected notification if the network is pending validation
+ // after the captive portal app was open, and it has now validated.
+ if (nai.captivePortalValidationPending && valid) {
+ // User is now logged in, network validated.
+ nai.captivePortalValidationPending = false;
showNetworkNotification(nai, NotificationType.LOGGED_IN);
}
@@ -2634,8 +2685,9 @@
}
if (valid != nai.lastValidated) {
if (wasDefault) {
- metricsLogger().defaultNetworkMetrics().logDefaultNetworkValidity(
- SystemClock.elapsedRealtime(), valid);
+ mDeps.getMetricsLogger()
+ .defaultNetworkMetrics().logDefaultNetworkValidity(
+ SystemClock.elapsedRealtime(), valid);
}
final int oldScore = nai.getCurrentScore();
nai.lastValidated = valid;
@@ -2645,25 +2697,38 @@
if (oldScore != nai.getCurrentScore()) sendUpdatedScoreToFactories(nai);
if (valid) {
handleFreshlyValidatedNetwork(nai);
- // Clear NO_INTERNET and LOST_INTERNET notifications if network becomes
- // valid.
+ // Clear NO_INTERNET, PARTIAL_CONNECTIVITY and LOST_INTERNET
+ // notifications if network becomes valid.
mNotifier.clearNotification(nai.network.netId,
NotificationType.NO_INTERNET);
mNotifier.clearNotification(nai.network.netId,
NotificationType.LOST_INTERNET);
+ mNotifier.clearNotification(nai.network.netId,
+ NotificationType.PARTIAL_CONNECTIVITY);
}
} else if (partialConnectivityChanged) {
- nai.partialConnectivity = partialConnectivity;
updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities);
}
updateInetCondition(nai);
// Let the NetworkAgent know the state of its network
Bundle redirectUrlBundle = new Bundle();
redirectUrlBundle.putString(NetworkAgent.REDIRECT_URL_KEY, redirectUrl);
+ // TODO: Evaluate to update partial connectivity to status to NetworkAgent.
nai.asyncChannel.sendMessage(
NetworkAgent.CMD_REPORT_NETWORK_STATUS,
(valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK),
0, redirectUrlBundle);
+
+ // If NetworkMonitor detects partial connectivity before
+ // EVENT_PROMPT_UNVALIDATED arrives, show the partial connectivity notification
+ // immediately. Re-notify partial connectivity silently if no internet
+ // notification already there.
+ if (!wasPartial && nai.partialConnectivity) {
+ // Remove delayed message if there is a pending message.
+ mHandler.removeMessages(EVENT_PROMPT_UNVALIDATED, nai.network);
+ handlePromptUnvalidated(nai.network);
+ }
+
if (wasValidated && !nai.lastValidated) {
handleNetworkUnvalidated(nai);
}
@@ -2678,9 +2743,6 @@
final int oldScore = nai.getCurrentScore();
nai.lastCaptivePortalDetected = visible;
nai.everCaptivePortalDetected |= visible;
- if (visible) {
- nai.captivePortalLoginNotified = false;
- }
if (nai.lastCaptivePortalDetected &&
Settings.Global.CAPTIVE_PORTAL_MODE_AVOID == getCaptivePortalMode()) {
if (DBG) log("Avoiding captive portal network: " + nai.name());
@@ -2765,29 +2827,31 @@
}
private class NetworkMonitorCallbacks extends INetworkMonitorCallbacks.Stub {
- private final NetworkAgentInfo mNai;
+ private final int mNetId;
+ private final AutodestructReference<NetworkAgentInfo> mNai;
private NetworkMonitorCallbacks(NetworkAgentInfo nai) {
- mNai = nai;
+ mNetId = nai.network.netId;
+ mNai = new AutodestructReference(nai);
}
@Override
public void onNetworkMonitorCreated(INetworkMonitor networkMonitor) {
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT,
- new Pair<>(mNai, networkMonitor)));
+ new Pair<>(mNai.getAndDestroy(), networkMonitor)));
}
@Override
public void notifyNetworkTested(int testResult, @Nullable String redirectUrl) {
mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage(EVENT_NETWORK_TESTED,
- testResult, mNai.network.netId, redirectUrl));
+ testResult, mNetId, redirectUrl));
}
@Override
public void notifyPrivateDnsConfigResolved(PrivateDnsConfigParcel config) {
mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage(
EVENT_PRIVATE_DNS_CONFIG_RESOLVED,
- 0, mNai.network.netId, PrivateDnsConfig.fromParcel(config)));
+ 0, mNetId, PrivateDnsConfig.fromParcel(config)));
}
@Override
@@ -2805,20 +2869,23 @@
}
mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage(
EVENT_PROVISIONING_NOTIFICATION, PROVISIONING_NOTIFICATION_SHOW,
- mNai.network.netId,
- pendingIntent));
+ mNetId, pendingIntent));
}
@Override
public void hideProvisioningNotification() {
mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage(
- EVENT_PROVISIONING_NOTIFICATION, PROVISIONING_NOTIFICATION_HIDE,
- mNai.network.netId));
+ EVENT_PROVISIONING_NOTIFICATION, PROVISIONING_NOTIFICATION_HIDE, mNetId));
+ }
+
+ @Override
+ public int getInterfaceVersion() {
+ return this.VERSION;
}
}
- private boolean networkRequiresValidation(NetworkAgentInfo nai) {
- return isValidationRequired(nai.networkCapabilities);
+ private boolean networkRequiresPrivateDnsValidation(NetworkAgentInfo nai) {
+ return isPrivateDnsValidationRequired(nai.networkCapabilities);
}
private void handleFreshlyValidatedNetwork(NetworkAgentInfo nai) {
@@ -2836,7 +2903,7 @@
for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
handlePerNetworkPrivateDnsConfig(nai, cfg);
- if (networkRequiresValidation(nai)) {
+ if (networkRequiresPrivateDnsValidation(nai)) {
handleUpdateLinkProperties(nai, new LinkProperties(nai.linkProperties));
}
}
@@ -2845,16 +2912,12 @@
private void handlePerNetworkPrivateDnsConfig(NetworkAgentInfo nai, PrivateDnsConfig cfg) {
// Private DNS only ever applies to networks that might provide
// Internet access and therefore also require validation.
- if (!networkRequiresValidation(nai)) return;
+ if (!networkRequiresPrivateDnsValidation(nai)) return;
// Notify the NetworkAgentInfo/NetworkMonitor in case NetworkMonitor needs to cancel or
// schedule DNS resolutions. If a DNS resolution is required the
// result will be sent back to us.
- try {
- nai.networkMonitor().notifyPrivateDnsChanged(cfg.toParcel());
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
+ nai.networkMonitor().notifyPrivateDnsChanged(cfg.toParcel());
// With Private DNS bypass support, we can proceed to update the
// Private DNS config immediately, even if we're in strict mode
@@ -2959,8 +3022,8 @@
final boolean wasDefault = isDefaultNetwork(nai);
synchronized (mNetworkForNetId) {
mNetworkForNetId.remove(nai.network.netId);
- mNetIdInUse.delete(nai.network.netId);
}
+ mNetIdManager.releaseNetId(nai.network.netId);
// Just in case.
mLegacyTypeTracker.remove(nai, wasDefault);
}
@@ -3007,7 +3070,7 @@
// if there is a fallback. Taken together, the two form a X -> 0, 0 -> Y sequence
// whose timestamps tell how long it takes to recover a default network.
long now = SystemClock.elapsedRealtime();
- metricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(now, null, nai);
+ mDeps.getMetricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(now, null, nai);
}
notifyIfacesChangedForNetworkStats();
// TODO - we shouldn't send CALLBACK_LOST to requests that can be satisfied
@@ -3020,11 +3083,7 @@
// Disable wakeup packet monitoring for each interface.
wakeupModifyInterface(iface, nai.networkCapabilities, false);
}
- try {
- nai.networkMonitor().notifyNetworkDisconnected();
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
+ nai.networkMonitor().notifyNetworkDisconnected();
mNetworkAgentInfos.remove(nai.messenger);
nai.clatd.update();
synchronized (mNetworkForNetId) {
@@ -3062,15 +3121,38 @@
// fallback network the default or requested a new network from the
// NetworkFactories, so network traffic isn't interrupted for an unnecessarily
// long time.
- try {
- mNetd.networkDestroy(nai.network.netId);
- } catch (RemoteException | ServiceSpecificException e) {
- loge("Exception destroying network: " + e);
- }
+ destroyNativeNetwork(nai);
mDnsManager.removeNetwork(nai.network);
}
- synchronized (mNetworkForNetId) {
- mNetIdInUse.delete(nai.network.netId);
+ mNetIdManager.releaseNetId(nai.network.netId);
+ }
+
+ private boolean createNativeNetwork(@NonNull NetworkAgentInfo networkAgent) {
+ try {
+ // This should never fail. Specifying an already in use NetID will cause failure.
+ if (networkAgent.isVPN()) {
+ mNetd.networkCreateVpn(networkAgent.network.netId,
+ (networkAgent.networkMisc == null
+ || !networkAgent.networkMisc.allowBypass));
+ } else {
+ mNetd.networkCreatePhysical(networkAgent.network.netId,
+ getNetworkPermission(networkAgent.networkCapabilities));
+ }
+ mDnsResolver.createNetworkCache(networkAgent.network.netId);
+ return true;
+ } catch (RemoteException | ServiceSpecificException e) {
+ loge("Error creating network " + networkAgent.network.netId + ": "
+ + e.getMessage());
+ return false;
+ }
+ }
+
+ private void destroyNativeNetwork(@NonNull NetworkAgentInfo networkAgent) {
+ try {
+ mNetd.networkDestroy(networkAgent.network.netId);
+ mDnsResolver.destroyNetworkCache(networkAgent.network.netId);
+ } catch (RemoteException | ServiceSpecificException e) {
+ loge("Exception destroying network: " + e);
}
}
@@ -3409,11 +3491,10 @@
// Inform NetworkMonitor that partial connectivity is acceptable. This will likely
// result in a partial connectivity result which will be processed by
// maybeHandleNetworkMonitorMessage.
- try {
- nai.networkMonitor().setAcceptPartialConnectivity();
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
+ //
+ // TODO: NetworkMonitor does not refer to the "never ask again" bit. The bit is stored
+ // per network. Therefore, NetworkMonitor may still do https probe.
+ nai.networkMonitor().setAcceptPartialConnectivity();
}
}
@@ -3445,11 +3526,7 @@
NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
if (nai == null) return;
if (!nai.networkCapabilities.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)) return;
- try {
- nai.networkMonitor().launchCaptivePortalApp();
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
+ nai.networkMonitor().launchCaptivePortalApp();
});
}
@@ -3463,7 +3540,8 @@
*/
@Override
public void startCaptivePortalAppInternal(Network network, Bundle appExtras) {
- mContext.checkCallingOrSelfPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
+ mContext.enforceCallingOrSelfPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ "ConnectivityService");
final Intent appIntent = new Intent(ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN);
appIntent.putExtras(appExtras);
@@ -3471,6 +3549,12 @@
new CaptivePortal(new CaptivePortalImpl(network).asBinder()));
appIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
+ // This runs on a random binder thread, but getNetworkAgentInfoForNetwork is thread-safe,
+ // and captivePortalValidationPending is volatile.
+ final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
+ if (nai != null) {
+ nai.captivePortalValidationPending = true;
+ }
Binder.withCleanCallingIdentity(() ->
mContext.startActivityAsUser(appIntent, UserHandle.CURRENT));
}
@@ -3483,7 +3567,7 @@
}
@Override
- public void appResponse(final int response) throws RemoteException {
+ public void appResponse(final int response) {
if (response == CaptivePortal.APP_RETURN_WANTED_AS_IS) {
enforceSettingsPermission();
}
@@ -3493,16 +3577,9 @@
if (nai == null) return;
// nai.networkMonitor() is thread-safe
- final INetworkMonitor nm = nai.networkMonitor();
+ final NetworkMonitorManager nm = nai.networkMonitor();
if (nm == null) return;
-
- final long token = Binder.clearCallingIdentity();
- try {
- nm.notifyCaptivePortalAppFinished(response);
- } finally {
- // Not using Binder.withCleanCallingIdentity() to keep the checked RemoteException
- Binder.restoreCallingIdentity(token);
- }
+ nm.notifyCaptivePortalAppFinished(response);
}
@Override
@@ -3578,21 +3655,31 @@
private void showNetworkNotification(NetworkAgentInfo nai, NotificationType type) {
final String action;
+ final boolean highPriority;
switch (type) {
case LOGGED_IN:
action = Settings.ACTION_WIFI_SETTINGS;
mHandler.removeMessages(EVENT_TIMEOUT_NOTIFICATION);
mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_TIMEOUT_NOTIFICATION,
nai.network.netId, 0), TIMEOUT_NOTIFICATION_DELAY_MS);
+ // High priority because it is a direct result of the user logging in to a portal.
+ highPriority = true;
break;
case NO_INTERNET:
action = ConnectivityManager.ACTION_PROMPT_UNVALIDATED;
+ // High priority because it is only displayed for explicitly selected networks.
+ highPriority = true;
break;
case LOST_INTERNET:
action = ConnectivityManager.ACTION_PROMPT_LOST_VALIDATION;
+ // High priority because it could help the user avoid unexpected data usage.
+ highPriority = true;
break;
case PARTIAL_CONNECTIVITY:
action = ConnectivityManager.ACTION_PROMPT_PARTIAL_CONNECTIVITY;
+ // Don't bother the user with a high-priority notification if the network was not
+ // explicitly selected by the user.
+ highPriority = nai.networkMisc.explicitlySelected;
break;
default:
Slog.wtf(TAG, "Unknown notification type " + type);
@@ -3609,25 +3696,50 @@
PendingIntent pendingIntent = PendingIntent.getActivityAsUser(
mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
- mNotifier.showNotification(nai.network.netId, type, nai, null, pendingIntent, true);
+
+ mNotifier.showNotification(nai.network.netId, type, nai, null, pendingIntent, highPriority);
+ }
+
+ private boolean shouldPromptUnvalidated(NetworkAgentInfo nai) {
+ // Don't prompt if the network is validated, and don't prompt on captive portals
+ // because we're already prompting the user to sign in.
+ if (nai.everValidated || nai.everCaptivePortalDetected) {
+ return false;
+ }
+
+ // If a network has partial connectivity, always prompt unless the user has already accepted
+ // partial connectivity and selected don't ask again. This ensures that if the device
+ // automatically connects to a network that has partial Internet access, the user will
+ // always be able to use it, either because they've already chosen "don't ask again" or
+ // because we have prompt them.
+ if (nai.partialConnectivity && !nai.networkMisc.acceptPartialConnectivity) {
+ return true;
+ }
+
+ // If a network has no Internet access, only prompt if the network was explicitly selected
+ // and if the user has not already told us to use the network regardless of whether it
+ // validated or not.
+ if (nai.networkMisc.explicitlySelected && !nai.networkMisc.acceptUnvalidated) {
+ return true;
+ }
+
+ return false;
}
private void handlePromptUnvalidated(Network network) {
if (VDBG || DDBG) log("handlePromptUnvalidated " + network);
NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
- // Only prompt if the network is unvalidated or network has partial internet connectivity
- // and was explicitly selected by the user, and if we haven't already been told to switch
- // to it regardless of whether it validated or not. Also don't prompt on captive portals
- // because we're already prompting the user to sign in.
- if (nai == null || nai.everValidated || nai.everCaptivePortalDetected
- || !nai.networkMisc.explicitlySelected || nai.networkMisc.acceptUnvalidated
- // TODO: Once the value of acceptPartialConnectivity is moved to IpMemoryStore,
- // we should reevaluate how to handle acceptPartialConnectivity when network just
- // connected.
- || nai.networkMisc.acceptPartialConnectivity) {
+ if (nai == null || !shouldPromptUnvalidated(nai)) {
return;
}
+
+ // Stop automatically reconnecting to this network in the future. Automatically connecting
+ // to a network that provides no or limited connectivity is not useful, because the user
+ // cannot use that network except through the notification shown by this method, and the
+ // notification is only shown if the network is explicitly selected by the user.
+ nai.asyncChannel.sendMessage(NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT);
+
// TODO: Evaluate if it's needed to wait 8 seconds for triggering notification when
// NetworkMonitor detects the network is partial connectivity. Need to change the design to
// popup the notification immediately when the network is partial connectivity.
@@ -4073,11 +4185,7 @@
if (isNetworkWithLinkPropertiesBlocked(lp, uid, false)) {
return;
}
- try {
- nai.networkMonitor().forceReevaluation(uid);
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
+ nai.networkMonitor().forceReevaluation(uid);
}
/**
@@ -4100,7 +4208,7 @@
return null;
}
return getLinkPropertiesProxyInfo(activeNetwork);
- } else if (queryUserAccess(Binder.getCallingUid(), network.netId)) {
+ } else if (mDeps.queryUserAccess(Binder.getCallingUid(), network.netId)) {
// Don't call getLinkProperties() as it requires ACCESS_NETWORK_STATE permission, which
// caller may not have.
return getLinkPropertiesProxyInfo(network);
@@ -4109,10 +4217,6 @@
return null;
}
- @VisibleForTesting
- protected boolean queryUserAccess(int uid, int netId) {
- return NetworkUtils.queryUserAccess(uid, netId);
- }
private ProxyInfo getLinkPropertiesProxyInfo(Network network) {
final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
@@ -4344,7 +4448,7 @@
// the underlyingNetworks list.
if (underlyingNetworks == null) {
NetworkAgentInfo defaultNai = getDefaultNetwork();
- if (defaultNai != null && defaultNai.linkProperties != null) {
+ if (defaultNai != null) {
underlyingNetworks = new Network[] { defaultNai.network };
}
}
@@ -4353,7 +4457,11 @@
for (Network network : underlyingNetworks) {
LinkProperties lp = getLinkProperties(network);
if (lp != null) {
- interfaces.add(lp.getInterfaceName());
+ for (String iface : lp.getAllInterfaceNames()) {
+ if (!TextUtils.isEmpty(iface)) {
+ interfaces.add(iface);
+ }
+ }
}
}
if (!interfaces.isEmpty()) {
@@ -4701,7 +4809,7 @@
final long ident = Binder.clearCallingIdentity();
try {
// Concatenate the range of types onto the range of NetIDs.
- int id = MAX_NET_ID + 1 + (networkType - ConnectivityManager.TYPE_NONE);
+ int id = NetIdManager.MAX_NET_ID + 1 + (networkType - ConnectivityManager.TYPE_NONE);
mNotifier.setProvNotificationVisible(visible, id, action);
} finally {
Binder.restoreCallingIdentity(ident);
@@ -5312,10 +5420,9 @@
@GuardedBy("mNetworkForNetId")
private final SparseArray<NetworkAgentInfo> mNetworkForNetId = new SparseArray<>();
// NOTE: Accessed on multiple threads, synchronized with mNetworkForNetId.
- // An entry is first added to mNetIdInUse, prior to mNetworkForNetId, so
+ // An entry is first reserved with NetIdManager, prior to being added to mNetworkForNetId, so
// there may not be a strict 1:1 correlation between the two.
- @GuardedBy("mNetworkForNetId")
- private final SparseBooleanArray mNetIdInUse = new SparseBooleanArray();
+ private final NetIdManager mNetIdManager;
// NetworkAgentInfo keyed off its connecting messenger
// TODO - eval if we can reduce the number of lists/hashmaps/sparsearrays
@@ -5371,7 +5478,8 @@
}
}
- private boolean isDefaultNetwork(NetworkAgentInfo nai) {
+ @VisibleForTesting
+ protected boolean isDefaultNetwork(NetworkAgentInfo nai) {
return nai == getDefaultNetwork();
}
@@ -5416,9 +5524,9 @@
// satisfies mDefaultRequest.
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, mDnsResolver,
- mNMS, factorySerialNumber);
+ new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
+ currentScore, mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd,
+ mDnsResolver, mNMS, factorySerialNumber);
// Make sure the network capabilities reflect what the agent info says.
nai.setNetworkCapabilities(mixInCapabilities(nai, nc));
final String extraInfo = networkInfo.getExtraInfo();
@@ -5427,7 +5535,7 @@
if (DBG) log("registerNetworkAgent " + nai);
final long token = Binder.clearCallingIdentity();
try {
- getNetworkStack().makeNetworkMonitor(
+ mDeps.getNetworkStack().makeNetworkMonitor(
nai.network, name, new NetworkMonitorCallbacks(nai));
} finally {
Binder.restoreCallingIdentity(token);
@@ -5439,11 +5547,6 @@
return nai.network.netId;
}
- @VisibleForTesting
- protected NetworkStackClient getNetworkStack() {
- return NetworkStackClient.getInstance();
- }
-
private void handleRegisterNetworkAgent(NetworkAgentInfo nai, INetworkMonitor networkMonitor) {
nai.onNetworkMonitorCreated(networkMonitor);
if (VDBG) log("Got NetworkAgent Messenger");
@@ -5455,11 +5558,10 @@
try {
networkMonitor.start();
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ e.rethrowAsRuntimeException();
}
nai.asyncChannel.connect(mContext, mTrackerHandler, nai.messenger);
NetworkInfo networkInfo = nai.networkInfo;
- nai.networkInfo = null;
updateNetworkInfo(nai, networkInfo);
updateUids(nai, null, nai.networkCapabilities);
}
@@ -5509,11 +5611,7 @@
// 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();
- }
+ networkAgent.networkMonitor().notifyLinkPropertiesChanged(newLp);
if (networkAgent.everConnected) {
notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED);
}
@@ -6257,7 +6355,7 @@
// Notify system services that this network is up.
makeDefault(newNetwork);
// Log 0 -> X and Y -> X default network transitions, where X is the new default.
- metricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(
+ mDeps.getMetricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(
now, newNetwork, oldDefaultNetwork);
// Have a new default network, release the transition wakelock in
scheduleReleaseNetworkTransitionWakelock();
@@ -6462,8 +6560,7 @@
if (DBG) {
log(networkAgent.name() + " EVENT_NETWORK_INFO_CHANGED, going from " +
- (oldInfo == null ? "null" : oldInfo.getState()) +
- " to " + state);
+ oldInfo.getState() + " to " + state);
}
if (!networkAgent.created
@@ -6473,21 +6570,7 @@
// A network that has just connected has zero requests and is thus a foreground network.
networkAgent.networkCapabilities.addCapability(NET_CAPABILITY_FOREGROUND);
- try {
- // This should never fail. Specifying an already in use NetID will cause failure.
- if (networkAgent.isVPN()) {
- mNMS.createVirtualNetwork(networkAgent.network.netId,
- (networkAgent.networkMisc == null ||
- !networkAgent.networkMisc.allowBypass));
- } else {
- mNMS.createPhysicalNetwork(networkAgent.network.netId,
- getNetworkPermission(networkAgent.networkCapabilities));
- }
- } catch (Exception e) {
- loge("Error creating network " + networkAgent.network.netId + ": "
- + e.getMessage());
- return;
- }
+ if (!createNativeNetwork(networkAgent)) return;
networkAgent.created = true;
}
@@ -6511,15 +6594,11 @@
// command must be sent after updating LinkProperties to maximize chances of
// NetworkMonitor seeing the correct LinkProperties when starting.
// TODO: pass LinkProperties to the NetworkMonitor in the notifyNetworkConnected call.
- try {
- if (networkAgent.networkMisc.acceptPartialConnectivity) {
- networkAgent.networkMonitor().setAcceptPartialConnectivity();
- }
- networkAgent.networkMonitor().notifyNetworkConnected(
- networkAgent.linkProperties, networkAgent.networkCapabilities);
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ if (networkAgent.networkMisc.acceptPartialConnectivity) {
+ networkAgent.networkMonitor().setAcceptPartialConnectivity();
}
+ networkAgent.networkMonitor().notifyNetworkConnected(
+ networkAgent.linkProperties, networkAgent.networkCapabilities);
scheduleUnvalidatedPrompt(networkAgent);
// Whether a particular NetworkRequest listen should cause signal strength thresholds to
@@ -6554,8 +6633,8 @@
// TODO(b/122649188): send the broadcast only to VPN users.
mProxyTracker.sendProxyBroadcast();
}
- } else if ((oldInfo != null && oldInfo.getState() == NetworkInfo.State.SUSPENDED) ||
- state == NetworkInfo.State.SUSPENDED) {
+ } else if (networkAgent.created && (oldInfo.getState() == NetworkInfo.State.SUSPENDED ||
+ state == NetworkInfo.State.SUSPENDED)) {
// going into or coming out of SUSPEND: re-score and notify
if (networkAgent.getCurrentScore() != oldScore) {
rematchAllNetworksAndRequests(networkAgent, oldScore);
@@ -6671,7 +6750,8 @@
}
}
- private void sendLegacyNetworkBroadcast(NetworkAgentInfo nai, DetailedState state, int type) {
+ @VisibleForTesting
+ protected void sendLegacyNetworkBroadcast(NetworkAgentInfo nai, DetailedState state, int type) {
// The NetworkInfo we actually send out has no bearing on the real
// state of affairs. For example, if the default connection is mobile,
// and a request for HIPRI has just gone away, we need to pretend that
@@ -6761,7 +6841,7 @@
/**
* Notify NetworkStatsService that the set of active ifaces has changed, or that one of the
- * properties tracked by NetworkStatsService on an active iface has changed.
+ * active iface's tracked properties has changed.
*/
private void notifyIfacesChangedForNetworkStats() {
ensureRunningOnConnectivityServiceThread();
@@ -6770,9 +6850,11 @@
if (activeLinkProperties != null) {
activeIface = activeLinkProperties.getInterfaceName();
}
+
+ final VpnInfo[] vpnInfos = getAllVpnInfo();
try {
mStatsService.forceUpdateIfaces(
- getDefaultNetworks(), getAllVpnInfo(), getAllNetworkState(), activeIface);
+ getDefaultNetworks(), getAllNetworkState(), activeIface, vpnInfos);
} catch (Exception ignored) {
}
}
@@ -6876,6 +6958,11 @@
final int userId = UserHandle.getCallingUserId();
+ Binder.withCleanCallingIdentity(() -> {
+ final IpMemoryStore ipMemoryStore = IpMemoryStore.getMemoryStore(mContext);
+ ipMemoryStore.factoryReset();
+ });
+
// Turn airplane mode off
setAirplaneMode(false);
@@ -6939,27 +7026,6 @@
return nwm.getWatchlistConfigHash();
}
- @VisibleForTesting
- MultinetworkPolicyTracker createMultinetworkPolicyTracker(Context c, Handler h, Runnable r) {
- return new MultinetworkPolicyTracker(c, h, r);
- }
-
- @VisibleForTesting
- public WakeupMessage makeWakeupMessage(Context c, Handler h, String s, int cmd, Object obj) {
- return new WakeupMessage(c, h, s, cmd, 0, 0, obj);
- }
-
- @VisibleForTesting
- public boolean hasService(String name) {
- return ServiceManager.checkService(name) != null;
- }
-
- @VisibleForTesting
- protected IpConnectivityMetrics.Logger metricsLogger() {
- return checkNotNull(LocalServices.getService(IpConnectivityMetrics.Logger.class),
- "no IpConnectivityMetrics service");
- }
-
private void logNetworkEvent(NetworkAgentInfo nai, int evtype) {
int[] transports = nai.networkCapabilities.getTransportTypes();
mMetricsLog.log(nai.network.netId, transports, new NetworkEvent(evtype));
diff --git a/services/core/java/com/android/server/NetIdManager.java b/services/core/java/com/android/server/NetIdManager.java
new file mode 100644
index 0000000..11533be
--- /dev/null
+++ b/services/core/java/com/android/server/NetIdManager.java
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+package com.android.server;
+
+import android.annotation.NonNull;
+import android.util.SparseBooleanArray;
+
+import com.android.internal.annotations.GuardedBy;
+
+/**
+ * Class used to reserve and release net IDs.
+ *
+ * <p>Instances of this class are thread-safe.
+ */
+public class NetIdManager {
+ // Sequence number for Networks; keep in sync with system/netd/NetworkController.cpp
+ public static final int MIN_NET_ID = 100; // some reserved marks
+ // Top IDs reserved by IpSecService
+ public static final int MAX_NET_ID = 65535 - IpSecService.TUN_INTF_NETID_RANGE;
+
+ @GuardedBy("mNetIdInUse")
+ private final SparseBooleanArray mNetIdInUse = new SparseBooleanArray();
+
+ @GuardedBy("mNetIdInUse")
+ private int mLastNetId = MIN_NET_ID - 1;
+
+ /**
+ * Get the first netId that follows the provided lastId and is available.
+ */
+ private static int getNextAvailableNetIdLocked(
+ int lastId, @NonNull SparseBooleanArray netIdInUse) {
+ int netId = lastId;
+ for (int i = MIN_NET_ID; i <= MAX_NET_ID; i++) {
+ netId = netId < MAX_NET_ID ? netId + 1 : MIN_NET_ID;
+ if (!netIdInUse.get(netId)) {
+ return netId;
+ }
+ }
+ throw new IllegalStateException("No free netIds");
+ }
+
+ /**
+ * Reserve a new ID for a network.
+ */
+ public int reserveNetId() {
+ synchronized (mNetIdInUse) {
+ mLastNetId = getNextAvailableNetIdLocked(mLastNetId, mNetIdInUse);
+ // Make sure NetID unused. http://b/16815182
+ mNetIdInUse.put(mLastNetId, true);
+ return mLastNetId;
+ }
+ }
+
+ /**
+ * Clear a previously reserved ID for a network.
+ */
+ public void releaseNetId(int id) {
+ synchronized (mNetIdInUse) {
+ mNetIdInUse.delete(id);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index 40bf7bc..d19d2dd 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -19,6 +19,7 @@
import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.INetd;
@@ -53,6 +54,7 @@
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
+import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;
/** @hide */
@@ -226,6 +228,8 @@
@NonNull Looper looper,
@NonNull Context context,
@NonNull String iface,
+ @Nullable LinkProperties lp,
+ boolean isMetered,
int callingUid,
@NonNull IBinder binder)
throws RemoteException, SocketException {
@@ -245,9 +249,19 @@
nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
nc.setNetworkSpecifier(new StringNetworkSpecifier(iface));
+ if (!isMetered) {
+ nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+ }
// Build LinkProperties
- LinkProperties lp = new LinkProperties();
+ if (lp == null) {
+ lp = new LinkProperties();
+ } else {
+ lp = new LinkProperties(lp);
+ // Use LinkAddress(es) from the interface itself to minimize how much the caller
+ // is trusted.
+ lp.setLinkAddresses(new ArrayList<>());
+ }
lp.setInterfaceName(iface);
// Find the currently assigned addresses, and add them to LinkProperties
@@ -284,7 +298,11 @@
* <p>This method provides a Network that is useful only for testing.
*/
@Override
- public void setupTestNetwork(@NonNull String iface, @NonNull IBinder binder) {
+ public void setupTestNetwork(
+ @NonNull String iface,
+ @Nullable LinkProperties lp,
+ boolean isMetered,
+ @NonNull IBinder binder) {
enforceTestNetworkPermissions(mContext);
checkNotNull(iface, "missing Iface");
@@ -315,6 +333,8 @@
mHandler.getLooper(),
mContext,
iface,
+ lp,
+ isMetered,
callingUid,
binder);
diff --git a/services/core/java/com/android/server/connectivity/AutodestructReference.java b/services/core/java/com/android/server/connectivity/AutodestructReference.java
new file mode 100644
index 0000000..009a43e
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/AutodestructReference.java
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+package com.android.server.connectivity;
+
+import android.annotation.NonNull;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * A ref that autodestructs at the first usage of it.
+ * @param <T> The type of the held object
+ * @hide
+ */
+public class AutodestructReference<T> {
+ private final AtomicReference<T> mHeld;
+ public AutodestructReference(@NonNull T obj) {
+ if (null == obj) throw new NullPointerException("Autodestruct reference to null");
+ mHeld = new AtomicReference<>(obj);
+ }
+
+ /** Get the ref and destruct it. NPE if already destructed. */
+ @NonNull
+ public T getAndDestroy() {
+ final T obj = mHeld.getAndSet(null);
+ if (null == obj) throw new NullPointerException("Already autodestructed");
+ return obj;
+ }
+}
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index e33392d..2321afb 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -263,12 +263,6 @@
}
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);
}
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 77a18e2..9bae902 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -29,6 +29,7 @@
import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS;
import static android.net.SocketKeepalive.ERROR_INVALID_NETWORK;
import static android.net.SocketKeepalive.ERROR_INVALID_SOCKET;
+import static android.net.SocketKeepalive.ERROR_UNSUPPORTED;
import static android.net.SocketKeepalive.MAX_INTERVAL_SEC;
import static android.net.SocketKeepalive.MIN_INTERVAL_SEC;
import static android.net.SocketKeepalive.NO_KEEPALIVE;
@@ -46,6 +47,7 @@
import android.net.SocketKeepalive.InvalidSocketException;
import android.net.TcpKeepalivePacketData;
import android.net.util.IpUtils;
+import android.net.util.KeepaliveUtils;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -57,6 +59,7 @@
import android.util.Log;
import android.util.Pair;
+import com.android.internal.R;
import com.android.internal.util.HexDump;
import com.android.internal.util.IndentingPrintWriter;
@@ -65,6 +68,7 @@
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
/**
@@ -90,10 +94,29 @@
@NonNull
private final Context mContext;
+ // Supported keepalive count for each transport type, can be configured through
+ // config_networkSupportedKeepaliveCount. For better error handling, use
+ // {@link getSupportedKeepalivesForNetworkCapabilities} instead of direct access.
+ @NonNull
+ private final int[] mSupportedKeepalives;
+
+ // Reserved privileged keepalive slots per transport. Caller's permission will be enforced if
+ // the number of remaining keepalive slots is less than or equal to the threshold.
+ private final int mReservedPrivilegedSlots;
+
+ // Allowed unprivileged keepalive slots per uid. Caller's permission will be enforced if
+ // the number of remaining keepalive slots is less than or equal to the threshold.
+ private final int mAllowedUnprivilegedSlotsForUid;
+
public KeepaliveTracker(Context context, Handler handler) {
mConnectivityServiceHandler = handler;
mTcpController = new TcpKeepaliveController(handler);
mContext = context;
+ mSupportedKeepalives = KeepaliveUtils.getSupportedKeepalives(mContext);
+ mReservedPrivilegedSlots = mContext.getResources().getInteger(
+ R.integer.config_reservedPrivilegedKeepaliveSlots);
+ mAllowedUnprivilegedSlotsForUid = mContext.getResources().getInteger(
+ R.integer.config_allowedUnprivilegedKeepalivePerUid);
}
/**
@@ -115,11 +138,6 @@
public static final int TYPE_NATT = 1;
public static final int TYPE_TCP = 2;
- // Max allowed unprivileged keepalive slots per network. Caller's permission will be
- // enforced if number of existing keepalives reach this limit.
- // TODO: consider making this limit configurable via resources.
- private static final int MAX_UNPRIVILEGED_SLOTS = 3;
-
// Keepalive slot. A small integer that identifies this keepalive among the ones handled
// by this network.
private int mSlot = NO_KEEPALIVE;
@@ -198,6 +216,7 @@
public String toString() {
return "KeepaliveInfo ["
+ + " type=" + mType
+ " network=" + mNai.network
+ " startedState=" + startedStateString(mStartedState)
+ " "
@@ -247,24 +266,54 @@
private int checkPermission() {
final HashMap<Integer, KeepaliveInfo> networkKeepalives = mKeepalives.get(mNai);
- int unprivilegedCount = 0;
if (networkKeepalives == null) {
return ERROR_INVALID_NETWORK;
}
- for (KeepaliveInfo ki : networkKeepalives.values()) {
- if (!ki.mPrivileged) {
- unprivilegedCount++;
- }
- if (unprivilegedCount >= MAX_UNPRIVILEGED_SLOTS) {
- return mPrivileged ? SUCCESS : ERROR_INSUFFICIENT_RESOURCES;
+
+ if (mPrivileged) return SUCCESS;
+
+ final int supported = KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(
+ mSupportedKeepalives, mNai.networkCapabilities);
+
+ int takenUnprivilegedSlots = 0;
+ for (final KeepaliveInfo ki : networkKeepalives.values()) {
+ if (!ki.mPrivileged) ++takenUnprivilegedSlots;
+ }
+ if (takenUnprivilegedSlots > supported - mReservedPrivilegedSlots) {
+ return ERROR_INSUFFICIENT_RESOURCES;
+ }
+
+ // Count unprivileged keepalives for the same uid across networks.
+ int unprivilegedCountSameUid = 0;
+ for (final HashMap<Integer, KeepaliveInfo> kaForNetwork : mKeepalives.values()) {
+ for (final KeepaliveInfo ki : kaForNetwork.values()) {
+ if (ki.mUid == mUid) {
+ unprivilegedCountSameUid++;
+ }
}
}
+ if (unprivilegedCountSameUid > mAllowedUnprivilegedSlotsForUid) {
+ return ERROR_INSUFFICIENT_RESOURCES;
+ }
+ return SUCCESS;
+ }
+
+ private int checkLimit() {
+ final HashMap<Integer, KeepaliveInfo> networkKeepalives = mKeepalives.get(mNai);
+ if (networkKeepalives == null) {
+ return ERROR_INVALID_NETWORK;
+ }
+ final int supported = KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(
+ mSupportedKeepalives, mNai.networkCapabilities);
+ if (supported == 0) return ERROR_UNSUPPORTED;
+ if (networkKeepalives.size() > supported) return ERROR_INSUFFICIENT_RESOURCES;
return SUCCESS;
}
private int isValid() {
synchronized (mNai) {
int error = checkInterval();
+ if (error == SUCCESS) error = checkLimit();
if (error == SUCCESS) error = checkPermission();
if (error == SUCCESS) error = checkNetworkConnected();
if (error == SUCCESS) error = checkSourceAddress();
@@ -279,6 +328,8 @@
Log.d(TAG, "Starting keepalive " + mSlot + " on " + mNai.name());
switch (mType) {
case TYPE_NATT:
+ mNai.asyncChannel.sendMessage(
+ CMD_ADD_KEEPALIVE_PACKET_FILTER, slot, 0 /* Unused */, mPacket);
mNai.asyncChannel
.sendMessage(CMD_START_SOCKET_KEEPALIVE, slot, mInterval, mPacket);
break;
@@ -289,9 +340,8 @@
handleStopKeepalive(mNai, mSlot, ERROR_INVALID_SOCKET);
return;
}
- mNai.asyncChannel
- .sendMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER, slot, 0 /* Unused */,
- mPacket);
+ mNai.asyncChannel.sendMessage(
+ CMD_ADD_KEEPALIVE_PACKET_FILTER, slot, 0 /* Unused */, mPacket);
// TODO: check result from apf and notify of failure as needed.
mNai.asyncChannel
.sendMessage(CMD_START_SOCKET_KEEPALIVE, slot, mInterval, mPacket);
@@ -327,14 +377,17 @@
return;
default:
mStartedState = STOPPING;
- if (mType == TYPE_NATT) {
- mNai.asyncChannel.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, mSlot);
- } else if (mType == TYPE_TCP) {
- mNai.asyncChannel.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, mSlot);
- mNai.asyncChannel.sendMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER, mSlot);
- mTcpController.stopSocketMonitor(mSlot);
- } else {
- Log.wtf(TAG, "Stopping keepalive with unknown type: " + mType);
+ switch (mType) {
+ case TYPE_TCP:
+ mTcpController.stopSocketMonitor(mSlot);
+ // fall through
+ case TYPE_NATT:
+ mNai.asyncChannel.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, mSlot);
+ mNai.asyncChannel.sendMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER,
+ mSlot);
+ break;
+ default:
+ Log.wtf(TAG, "Stopping keepalive with unknown type: " + mType);
}
}
@@ -410,14 +463,16 @@
}
public void handleStopAllKeepalives(NetworkAgentInfo nai, int reason) {
- HashMap <Integer, KeepaliveInfo> networkKeepalives = mKeepalives.get(nai);
+ final HashMap<Integer, KeepaliveInfo> networkKeepalives = mKeepalives.get(nai);
if (networkKeepalives != null) {
- for (KeepaliveInfo ki : networkKeepalives.values()) {
+ final ArrayList<KeepaliveInfo> kalist = new ArrayList(networkKeepalives.values());
+ for (KeepaliveInfo ki : kalist) {
ki.stop(reason);
+ // Clean up keepalives since the network agent is disconnected and unable to pass
+ // back asynchronous result of stop().
+ cleanupStoppedKeepalive(nai, ki.mSlot);
}
}
- // Clean up keepalives will be done as a result of calling ki.stop() after the slots are
- // freed.
}
public void handleStopKeepalive(NetworkAgentInfo nai, int slot, int reason) {
@@ -507,7 +562,7 @@
if (KeepaliveInfo.STARTING == ki.mStartedState) {
if (SUCCESS == reason) {
// Keepalive successfully started.
- if (DBG) Log.d(TAG, "Started keepalive " + slot + " on " + nai.name());
+ Log.d(TAG, "Started keepalive " + slot + " on " + nai.name());
ki.mStartedState = KeepaliveInfo.STARTED;
try {
ki.mCallback.onStarted(slot);
@@ -669,6 +724,9 @@
}
public void dump(IndentingPrintWriter pw) {
+ pw.println("Supported Socket keepalives: " + Arrays.toString(mSupportedKeepalives));
+ pw.println("Reserved Privileged keepalives: " + mReservedPrivilegedSlots);
+ pw.println("Allowed Unprivileged keepalives per uid: " + mAllowedUnprivilegedSlotsForUid);
pw.println("Socket keepalives:");
pw.increaseIndent();
for (NetworkAgentInfo nai : mKeepalives.keySet()) {
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index cfa9131..96b7cb3 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -16,6 +16,7 @@
package com.android.server.connectivity;
+import android.annotation.NonNull;
import android.content.Context;
import android.net.IDnsResolver;
import android.net.INetd;
@@ -25,12 +26,12 @@
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkMisc;
+import android.net.NetworkMonitorManager;
import android.net.NetworkRequest;
import android.net.NetworkState;
import android.os.Handler;
import android.os.INetworkManagementService;
import android.os.Messenger;
-import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Log;
import android.util.SparseArray;
@@ -116,7 +117,7 @@
// not, ConnectivityService disconnects the NetworkAgent's AsyncChannel.
public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
- public NetworkInfo networkInfo;
+ @NonNull public NetworkInfo networkInfo;
// This Network object should always be used if possible, so as to encourage reuse of the
// enclosed socket factory and connection pool. Avoid creating other Network objects.
// This Network object is always valid.
@@ -155,9 +156,9 @@
// Whether a captive portal was found during the last network validation attempt.
public boolean lastCaptivePortalDetected;
- // Indicates the user was notified of a successful captive portal login since a portal was
- // last detected.
- public boolean captivePortalLoginNotified;
+ // Indicates the captive portal app was opened to show a login UI to the user, but the network
+ // has not validated yet.
+ public volatile boolean captivePortalValidationPending;
// Set to true when partial connectivity was detected.
public boolean partialConnectivity;
@@ -247,7 +248,7 @@
public final Nat464Xlat clatd;
// Set after asynchronous creation of the NetworkMonitor.
- private volatile INetworkMonitor mNetworkMonitor;
+ private volatile NetworkMonitorManager mNetworkMonitor;
private static final String TAG = ConnectivityService.class.getSimpleName();
private static final boolean VDBG = false;
@@ -278,7 +279,7 @@
* Inform NetworkAgentInfo that a new NetworkMonitor was created.
*/
public void onNetworkMonitorCreated(INetworkMonitor networkMonitor) {
- mNetworkMonitor = networkMonitor;
+ mNetworkMonitor = new NetworkMonitorManager(networkMonitor);
}
/**
@@ -290,13 +291,9 @@
*/
public void setNetworkCapabilities(NetworkCapabilities nc) {
networkCapabilities = nc;
- final INetworkMonitor nm = mNetworkMonitor;
+ final NetworkMonitorManager nm = mNetworkMonitor;
if (nm != null) {
- try {
- nm.notifyNetworkCapabilitiesChanged(nc);
- } catch (RemoteException e) {
- Log.e(TAG, "Error notifying NetworkMonitor of updated NetworkCapabilities", e);
- }
+ nm.notifyNetworkCapabilitiesChanged(nc);
}
}
@@ -317,11 +314,11 @@
}
/**
- * Get the INetworkMonitor in this NetworkAgentInfo.
+ * Get the NetworkMonitorManager in this NetworkAgentInfo.
*
* <p>This will be null before {@link #onNetworkMonitorCreated(INetworkMonitor)} is called.
*/
- public INetworkMonitor networkMonitor() {
+ public NetworkMonitorManager networkMonitor() {
return mNetworkMonitor;
}
@@ -483,11 +480,11 @@
// down an explicitly selected network before the user gets a chance to prefer it when
// a higher-scoring network (e.g., Ethernet) is available.
if (networkMisc.explicitlySelected && (networkMisc.acceptUnvalidated || pretendValidated)) {
- return ConnectivityConstants.MAXIMUM_NETWORK_SCORE;
+ return ConnectivityConstants.EXPLICITLY_SELECTED_NETWORK_SCORE;
}
int score = currentScore;
- if (!lastValidated && !pretendValidated && !ignoreWifiUnvalidationPenalty()) {
+ if (!lastValidated && !pretendValidated && !ignoreWifiUnvalidationPenalty() && !isVPN()) {
score -= ConnectivityConstants.UNVALIDATED_SCORE_PENALTY;
}
if (score < 0) score = 0;
@@ -583,10 +580,12 @@
}
if (newExpiry > 0) {
- mLingerMessage = mConnService.makeWakeupMessage(
+ mLingerMessage = new WakeupMessage(
mContext, mHandler,
- "NETWORK_LINGER_COMPLETE." + network.netId,
- EVENT_NETWORK_LINGER_COMPLETE, this);
+ "NETWORK_LINGER_COMPLETE." + network.netId /* cmdName */,
+ EVENT_NETWORK_LINGER_COMPLETE /* cmd */,
+ 0 /* arg1 (unused) */, 0 /* arg2 (unused) */,
+ this /* obj (NetworkAgentInfo) */);
mLingerMessage.schedule(newExpiry);
}
@@ -633,7 +632,7 @@
+ "acceptUnvalidated{" + networkMisc.acceptUnvalidated + "} "
+ "everCaptivePortalDetected{" + everCaptivePortalDetected + "} "
+ "lastCaptivePortalDetected{" + lastCaptivePortalDetected + "} "
- + "captivePortalLoginNotified{" + captivePortalLoginNotified + "} "
+ + "captivePortalValidationPending{" + captivePortalValidationPending + "} "
+ "partialConnectivity{" + partialConnectivity + "} "
+ "acceptPartialConnectivity{" + networkMisc.acceptPartialConnectivity + "} "
+ "clat{" + clatd + "} "
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index ac3d6de..077c405 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -19,7 +19,6 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
-import static android.telephony.SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
import android.app.Notification;
import android.app.NotificationManager;
@@ -107,10 +106,14 @@
}
}
- private static int getIcon(int transportType) {
- return (transportType == TRANSPORT_WIFI) ?
- R.drawable.stat_notify_wifi_in_range : // TODO: Distinguish ! from ?.
- R.drawable.stat_notify_rssi_in_range;
+ private static int getIcon(int transportType, NotificationType notifyType) {
+ if (transportType != TRANSPORT_WIFI) {
+ return R.drawable.stat_notify_rssi_in_range;
+ }
+
+ return notifyType == NotificationType.LOGGED_IN
+ ? R.drawable.ic_wifi_signal_4
+ : R.drawable.stat_notify_wifi_in_range; // TODO: Distinguish ! from ?.
}
/**
@@ -127,6 +130,7 @@
* @param id an identifier that uniquely identifies this notification. This must match
* between show and hide calls. We use the NetID value but for legacy callers
* we concatenate the range of types with the range of NetIDs.
+ * @param notifyType the type of the notification.
* @param nai the network with which the notification is associated. For a SIGN_IN, NO_INTERNET,
* or LOST_INTERNET notification, this is the network we're connecting to. For a
* NETWORK_SWITCH notification it's the network that we switched from. When this network
@@ -173,7 +177,7 @@
Resources r = Resources.getSystem();
CharSequence title;
CharSequence details;
- int icon = getIcon(transportType);
+ int icon = getIcon(transportType, notifyType);
if (notifyType == NotificationType.NO_INTERNET && transportType == TRANSPORT_WIFI) {
title = r.getString(R.string.wifi_no_internet,
WifiInfo.removeDoubleQuotes(nai.networkCapabilities.getSSID()));
@@ -228,14 +232,25 @@
title = r.getString(R.string.network_switch_metered, toTransport);
details = r.getString(R.string.network_switch_metered_detail, toTransport,
fromTransport);
+ } else if (notifyType == NotificationType.NO_INTERNET
+ || notifyType == NotificationType.PARTIAL_CONNECTIVITY) {
+ // NO_INTERNET and PARTIAL_CONNECTIVITY notification for non-WiFi networks
+ // are sent, but they are not implemented yet.
+ return;
} else {
Slog.wtf(TAG, "Unknown notification type " + notifyType + " on network transport "
+ getTransportName(transportType));
return;
}
-
- final String channelId = highPriority ? SystemNotificationChannels.NETWORK_ALERTS :
- SystemNotificationChannels.NETWORK_STATUS;
+ // When replacing an existing notification for a given network, don't alert, just silently
+ // update the existing notification. Note that setOnlyAlertOnce() will only work for the
+ // same id, and the id used here is the NotificationType which is different in every type of
+ // notification. This is required because the notification metrics only track the ID but not
+ // the tag.
+ final boolean hasPreviousNotification = previousNotifyType != null;
+ final String channelId = (highPriority && !hasPreviousNotification)
+ ? SystemNotificationChannels.NETWORK_ALERTS
+ : SystemNotificationChannels.NETWORK_STATUS;
Notification.Builder builder = new Notification.Builder(mContext, channelId)
.setWhen(System.currentTimeMillis())
.setShowWhen(notifyType == NotificationType.NETWORK_SWITCH)
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index f8582cd..fbe2589 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -199,15 +199,13 @@
ArraySet<String> perms = systemPermission.valueAt(i);
int uid = systemPermission.keyAt(i);
int netdPermission = 0;
- // Get the uids of native services that have UPDATE_DEVICE_STATS permission.
+ // Get the uids of native services that have UPDATE_DEVICE_STATS or INTERNET permission.
if (perms != null) {
netdPermission |= perms.contains(UPDATE_DEVICE_STATS)
? INetd.PERMISSION_UPDATE_DEVICE_STATS : 0;
+ netdPermission |= perms.contains(INTERNET)
+ ? INetd.PERMISSION_INTERNET : 0;
}
- // For internet permission, the native services have their own selinux domains and
- // sepolicy will control the socket creation during run time. netd cannot block the
- // socket creation based on the permission information here.
- netdPermission |= INetd.PERMISSION_INTERNET;
netdPermsUids.put(uid, netdPermsUids.get(uid) | netdPermission);
}
log("Users: " + mUsers.size() + ", Apps: " + mApps.size());
@@ -650,7 +648,7 @@
case INetd.PERMISSION_UPDATE_DEVICE_STATS:
updateStatsPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
break;
- case INetd.NO_PERMISSIONS:
+ case INetd.PERMISSION_NONE:
noPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
break;
case INetd.PERMISSION_UNINSTALLED:
@@ -676,7 +674,7 @@
ArrayUtils.convertToIntArray(updateStatsPermissionAppIds));
}
if (noPermissionAppIds.size() != 0) {
- mNetd.trafficSetNetPermForUids(INetd.NO_PERMISSIONS,
+ mNetd.trafficSetNetPermForUids(INetd.PERMISSION_NONE,
ArrayUtils.convertToIntArray(noPermissionAppIds));
}
if (uninstalledAppIds.size() != 0) {
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
index 9098f90..502aa97 100644
--- a/tests/net/Android.bp
+++ b/tests/net/Android.bp
@@ -3,21 +3,6 @@
//########################################################################
java_defaults {
name: "FrameworksNetTests-jni-defaults",
- static_libs: [
- "FrameworksNetCommonTests",
- "frameworks-base-testutils",
- "framework-protos",
- "androidx.test.rules",
- "mockito-target-minus-junit4",
- "platform-test-annotations",
- "services.core",
- "services.net",
- ],
- libs: [
- "android.test.runner",
- "android.test.base",
- "android.test.mock",
- ],
jni_libs: [
"ld-android",
"libartbase",
@@ -43,28 +28,45 @@
"libnativehelper",
"libnetdbpf",
"libnetdutils",
+ "libnetworkstatsfactorytestjni",
"libpackagelistparser",
"libpcre2",
"libprocessgroup",
"libselinux",
- "libui",
- "libutils",
- "libvndksupport",
"libtinyxml2",
+ "libui",
"libunwindstack",
+ "libutils",
"libutilscallstack",
+ "libvndksupport",
"libziparchive",
"libz",
- "netd_aidl_interface-cpp",
- "libnetworkstatsfactorytestjni",
+ "netd_aidl_interface-V2-cpp",
],
}
android_test {
name: "FrameworksNetTests",
defaults: ["FrameworksNetTests-jni-defaults"],
- srcs: ["java/**/*.java"],
+ srcs: ["java/**/*.java", "java/**/*.kt"],
platform_apis: true,
test_suites: ["device-tests"],
certificate: "platform",
+ static_libs: [
+ "androidx.test.rules",
+ "FrameworksNetCommonTests",
+ "frameworks-base-testutils",
+ "frameworks-net-integration-testutils",
+ "framework-protos",
+ "mockito-target-minus-junit4",
+ "net-tests-utils",
+ "platform-test-annotations",
+ "services.core",
+ "services.net",
+ ],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ "android.test.mock",
+ ],
}
diff --git a/tests/net/common/Android.bp b/tests/net/common/Android.bp
index 0a1ac75..e44d460 100644
--- a/tests/net/common/Android.bp
+++ b/tests/net/common/Android.bp
@@ -18,12 +18,15 @@
// They must be fast and stable, and exercise public or test APIs.
java_library {
name: "FrameworksNetCommonTests",
- srcs: ["java/**/*.java"],
+ srcs: ["java/**/*.java", "java/**/*.kt"],
static_libs: [
"androidx.test.rules",
"junit",
+ "mockito-target-minus-junit4",
+ "net-tests-utils",
+ "platform-test-annotations",
],
libs: [
"android.test.base.stubs",
],
-}
\ No newline at end of file
+}
diff --git a/tests/net/common/java/android/net/CaptivePortalTest.java b/tests/net/common/java/android/net/CaptivePortalTest.java
new file mode 100644
index 0000000..eed7159
--- /dev/null
+++ b/tests/net/common/java/android/net/CaptivePortalTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+package android.net;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.RemoteException;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class CaptivePortalTest {
+ private static final int DEFAULT_TIMEOUT_MS = 5000;
+ private static final String TEST_PACKAGE_NAME = "com.google.android.test";
+
+ private final class MyCaptivePortalImpl extends ICaptivePortal.Stub {
+ int mCode = -1;
+ String mPackageName = null;
+
+ @Override
+ public void appResponse(final int response) throws RemoteException {
+ mCode = response;
+ }
+
+ @Override
+ public void logEvent(int eventId, String packageName) throws RemoteException {
+ mCode = eventId;
+ mPackageName = packageName;
+ }
+ }
+
+ private interface TestFunctor {
+ void useCaptivePortal(CaptivePortal o);
+ }
+
+ private MyCaptivePortalImpl runCaptivePortalTest(TestFunctor f) {
+ final MyCaptivePortalImpl cp = new MyCaptivePortalImpl();
+ f.useCaptivePortal(new CaptivePortal(cp.asBinder()));
+ return cp;
+ }
+
+ @Test
+ public void testReportCaptivePortalDismissed() {
+ final MyCaptivePortalImpl result =
+ runCaptivePortalTest(c -> c.reportCaptivePortalDismissed());
+ assertEquals(result.mCode, CaptivePortal.APP_RETURN_DISMISSED);
+ }
+
+ @Test
+ public void testIgnoreNetwork() {
+ final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.ignoreNetwork());
+ assertEquals(result.mCode, CaptivePortal.APP_RETURN_UNWANTED);
+ }
+
+ @Test
+ public void testUseNetwork() {
+ final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.useNetwork());
+ assertEquals(result.mCode, CaptivePortal.APP_RETURN_WANTED_AS_IS);
+ }
+
+ @Test
+ public void testLogEvent() {
+ final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.logEvent(
+ MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_ACTIVITY,
+ TEST_PACKAGE_NAME));
+ assertEquals(result.mCode, MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_ACTIVITY);
+ assertEquals(result.mPackageName, TEST_PACKAGE_NAME);
+ }
+}
diff --git a/tests/net/common/java/android/net/IpPrefixTest.java b/tests/net/common/java/android/net/IpPrefixTest.java
index 719960d..985e10d 100644
--- a/tests/net/common/java/android/net/IpPrefixTest.java
+++ b/tests/net/common/java/android/net/IpPrefixTest.java
@@ -16,16 +16,18 @@
package android.net;
+import static com.android.testutils.MiscAssertsKt.assertEqualBothWays;
+import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals;
+import static com.android.testutils.MiscAssertsKt.assertNotEqualEitherWay;
+import static com.android.testutils.ParcelUtilsKt.assertParcelingIsLossless;
+
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import android.os.Parcel;
-
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -171,56 +173,46 @@
}
- private void assertAreEqual(Object o1, Object o2) {
- assertTrue(o1.equals(o2));
- assertTrue(o2.equals(o1));
- }
-
- private void assertAreNotEqual(Object o1, Object o2) {
- assertFalse(o1.equals(o2));
- assertFalse(o2.equals(o1));
- }
-
@Test
public void testEquals() {
IpPrefix p1, p2;
p1 = new IpPrefix("192.0.2.251/23");
p2 = new IpPrefix(new byte[]{(byte) 192, (byte) 0, (byte) 2, (byte) 251}, 23);
- assertAreEqual(p1, p2);
+ assertEqualBothWays(p1, p2);
p1 = new IpPrefix("192.0.2.5/23");
- assertAreEqual(p1, p2);
+ assertEqualBothWays(p1, p2);
p1 = new IpPrefix("192.0.2.5/24");
- assertAreNotEqual(p1, p2);
+ assertNotEqualEitherWay(p1, p2);
p1 = new IpPrefix("192.0.4.5/23");
- assertAreNotEqual(p1, p2);
+ assertNotEqualEitherWay(p1, p2);
p1 = new IpPrefix("2001:db8:dead:beef:f00::80/122");
p2 = new IpPrefix(IPV6_BYTES, 122);
assertEquals("2001:db8:dead:beef:f00::80/122", p2.toString());
- assertAreEqual(p1, p2);
+ assertEqualBothWays(p1, p2);
p1 = new IpPrefix("2001:db8:dead:beef:f00::bf/122");
- assertAreEqual(p1, p2);
+ assertEqualBothWays(p1, p2);
p1 = new IpPrefix("2001:db8:dead:beef:f00::8:0/123");
- assertAreNotEqual(p1, p2);
+ assertNotEqualEitherWay(p1, p2);
p1 = new IpPrefix("2001:db8:dead:beef::/122");
- assertAreNotEqual(p1, p2);
+ assertNotEqualEitherWay(p1, p2);
// 192.0.2.4/32 != c000:0204::/32.
byte[] ipv6bytes = new byte[16];
System.arraycopy(IPV4_BYTES, 0, ipv6bytes, 0, IPV4_BYTES.length);
p1 = new IpPrefix(ipv6bytes, 32);
- assertAreEqual(p1, new IpPrefix("c000:0204::/32"));
+ assertEqualBothWays(p1, new IpPrefix("c000:0204::/32"));
p2 = new IpPrefix(IPV4_BYTES, 32);
- assertAreNotEqual(p1, p2);
+ assertNotEqualEitherWay(p1, p2);
}
@Test
@@ -356,25 +348,6 @@
assertEquals(InetAddress.parseNumericAddress("192.0.2.0"), p.getAddress());
}
- public IpPrefix passThroughParcel(IpPrefix p) {
- Parcel parcel = Parcel.obtain();
- IpPrefix p2 = null;
- try {
- p.writeToParcel(parcel, 0);
- parcel.setDataPosition(0);
- p2 = IpPrefix.CREATOR.createFromParcel(parcel);
- } finally {
- parcel.recycle();
- }
- assertNotNull(p2);
- return p2;
- }
-
- public void assertParcelingIsLossless(IpPrefix p) {
- IpPrefix p2 = passThroughParcel(p);
- assertEquals(p, p2);
- }
-
@Test
public void testParceling() {
IpPrefix p;
@@ -386,5 +359,7 @@
p = new IpPrefix("192.0.2.0/25");
assertParcelingIsLossless(p);
assertTrue(p.isIPv4());
+
+ assertFieldCountEquals(2, IpPrefix.class);
}
}
diff --git a/tests/net/java/android/net/LinkAddressTest.java b/tests/net/common/java/android/net/LinkAddressTest.java
similarity index 89%
rename from tests/net/java/android/net/LinkAddressTest.java
rename to tests/net/common/java/android/net/LinkAddressTest.java
index d462441..b2e573b 100644
--- a/tests/net/java/android/net/LinkAddressTest.java
+++ b/tests/net/common/java/android/net/LinkAddressTest.java
@@ -27,15 +27,17 @@
import static android.system.OsConstants.RT_SCOPE_SITE;
import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
+import static com.android.testutils.MiscAssertsKt.assertEqualBothWays;
+import static com.android.testutils.MiscAssertsKt.assertNotEqualEitherWay;
+import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
+import static com.android.testutils.ParcelUtilsKt.assertParcelingIsLossless;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import android.os.Parcel;
-
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -217,67 +219,56 @@
l1.isSameAddressAs(l2));
}
- private void assertLinkAddressesEqual(LinkAddress l1, LinkAddress l2) {
- assertTrue(l1 + " unexpectedly not equal to " + l2, l1.equals(l2));
- assertTrue(l2 + " unexpectedly not equal to " + l1, l2.equals(l1));
- assertEquals(l1.hashCode(), l2.hashCode());
- }
-
- private void assertLinkAddressesNotEqual(LinkAddress l1, LinkAddress l2) {
- assertFalse(l1 + " unexpectedly equal to " + l2, l1.equals(l2));
- assertFalse(l2 + " unexpectedly equal to " + l1, l2.equals(l1));
- }
-
@Test
public void testEqualsAndSameAddressAs() {
LinkAddress l1, l2, l3;
l1 = new LinkAddress("2001:db8::1/64");
l2 = new LinkAddress("2001:db8::1/64");
- assertLinkAddressesEqual(l1, l2);
+ assertEqualBothWays(l1, l2);
assertIsSameAddressAs(l1, l2);
l2 = new LinkAddress("2001:db8::1/65");
- assertLinkAddressesNotEqual(l1, l2);
+ assertNotEqualEitherWay(l1, l2);
assertIsNotSameAddressAs(l1, l2);
l2 = new LinkAddress("2001:db8::2/64");
- assertLinkAddressesNotEqual(l1, l2);
+ assertNotEqualEitherWay(l1, l2);
assertIsNotSameAddressAs(l1, l2);
l1 = new LinkAddress("192.0.2.1/24");
l2 = new LinkAddress("192.0.2.1/24");
- assertLinkAddressesEqual(l1, l2);
+ assertEqualBothWays(l1, l2);
assertIsSameAddressAs(l1, l2);
l2 = new LinkAddress("192.0.2.1/23");
- assertLinkAddressesNotEqual(l1, l2);
+ assertNotEqualEitherWay(l1, l2);
assertIsNotSameAddressAs(l1, l2);
l2 = new LinkAddress("192.0.2.2/24");
- assertLinkAddressesNotEqual(l1, l2);
+ assertNotEqualEitherWay(l1, l2);
assertIsNotSameAddressAs(l1, l2);
// Check equals() and isSameAddressAs() on identical addresses with different flags.
l1 = new LinkAddress(V6_ADDRESS, 64);
l2 = new LinkAddress(V6_ADDRESS, 64, 0, RT_SCOPE_UNIVERSE);
- assertLinkAddressesEqual(l1, l2);
+ assertEqualBothWays(l1, l2);
assertIsSameAddressAs(l1, l2);
l2 = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED, RT_SCOPE_UNIVERSE);
- assertLinkAddressesNotEqual(l1, l2);
+ assertNotEqualEitherWay(l1, l2);
assertIsSameAddressAs(l1, l2);
// Check equals() and isSameAddressAs() on identical addresses with different scope.
l1 = new LinkAddress(V4_ADDRESS, 24);
l2 = new LinkAddress(V4_ADDRESS, 24, 0, RT_SCOPE_UNIVERSE);
- assertLinkAddressesEqual(l1, l2);
+ assertEqualBothWays(l1, l2);
assertIsSameAddressAs(l1, l2);
l2 = new LinkAddress(V4_ADDRESS, 24, 0, RT_SCOPE_HOST);
- assertLinkAddressesNotEqual(l1, l2);
+ assertNotEqualEitherWay(l1, l2);
assertIsSameAddressAs(l1, l2);
// Addresses with the same start or end bytes aren't equal between families.
@@ -291,10 +282,10 @@
assertTrue(Arrays.equals(ipv4Bytes, l2FirstIPv6Bytes));
assertTrue(Arrays.equals(ipv4Bytes, l3LastIPv6Bytes));
- assertLinkAddressesNotEqual(l1, l2);
+ assertNotEqualEitherWay(l1, l2);
assertIsNotSameAddressAs(l1, l2);
- assertLinkAddressesNotEqual(l1, l3);
+ assertNotEqualEitherWay(l1, l3);
assertIsNotSameAddressAs(l1, l3);
// Because we use InetAddress, an IPv4 address is equal to its IPv4-mapped address.
@@ -302,7 +293,7 @@
String addressString = V4 + "/24";
l1 = new LinkAddress(addressString);
l2 = new LinkAddress("::ffff:" + addressString);
- assertLinkAddressesEqual(l1, l2);
+ assertEqualBothWays(l1, l2);
assertIsSameAddressAs(l1, l2);
}
@@ -319,25 +310,6 @@
assertNotEquals(l1.hashCode(), l2.hashCode());
}
- private LinkAddress passThroughParcel(LinkAddress l) {
- Parcel p = Parcel.obtain();
- LinkAddress l2 = null;
- try {
- l.writeToParcel(p, 0);
- p.setDataPosition(0);
- l2 = LinkAddress.CREATOR.createFromParcel(p);
- } finally {
- p.recycle();
- }
- assertNotNull(l2);
- return l2;
- }
-
- private void assertParcelingIsLossless(LinkAddress l) {
- LinkAddress l2 = passThroughParcel(l);
- assertEquals(l, l2);
- }
-
@Test
public void testParceling() {
LinkAddress l;
@@ -346,7 +318,7 @@
assertParcelingIsLossless(l);
l = new LinkAddress(V4 + "/28", IFA_F_PERMANENT, RT_SCOPE_LINK);
- assertParcelingIsLossless(l);
+ assertParcelSane(l, 4);
}
private void assertGlobalPreferred(LinkAddress l, String msg) {
diff --git a/tests/net/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java
similarity index 77%
rename from tests/net/java/android/net/LinkPropertiesTest.java
rename to tests/net/common/java/android/net/LinkPropertiesTest.java
index 4177291..b0464d9 100644
--- a/tests/net/java/android/net/LinkPropertiesTest.java
+++ b/tests/net/common/java/android/net/LinkPropertiesTest.java
@@ -16,8 +16,11 @@
package android.net;
+import static com.android.testutils.ParcelUtilsKt.assertParcelingIsLossless;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -30,8 +33,6 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.internal.util.TestUtils;
-
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -46,28 +47,80 @@
@RunWith(AndroidJUnit4.class)
@SmallTest
public class LinkPropertiesTest {
- private static InetAddress ADDRV4 = NetworkUtils.numericToInetAddress("75.208.6.1");
- private static InetAddress ADDRV6 = NetworkUtils.numericToInetAddress(
+ private static final InetAddress ADDRV4 = InetAddresses.parseNumericAddress("75.208.6.1");
+ private static final InetAddress ADDRV6 = InetAddresses.parseNumericAddress(
"2001:0db8:85a3:0000:0000:8a2e:0370:7334");
- private static InetAddress DNS1 = NetworkUtils.numericToInetAddress("75.208.7.1");
- private static InetAddress DNS2 = NetworkUtils.numericToInetAddress("69.78.7.1");
- private static InetAddress DNS6 = NetworkUtils.numericToInetAddress("2001:4860:4860::8888");
- private static InetAddress PCSCFV6 = NetworkUtils.numericToInetAddress(
+ private static final InetAddress DNS1 = InetAddresses.parseNumericAddress("75.208.7.1");
+ private static final InetAddress DNS2 = InetAddresses.parseNumericAddress("69.78.7.1");
+ private static final InetAddress DNS6 = InetAddresses.parseNumericAddress(
+ "2001:4860:4860::8888");
+ private static final InetAddress PRIVDNS1 = InetAddresses.parseNumericAddress("1.1.1.1");
+ private static final InetAddress PRIVDNS2 = InetAddresses.parseNumericAddress("1.0.0.1");
+ private static final InetAddress PRIVDNS6 = InetAddresses.parseNumericAddress(
+ "2606:4700:4700::1111");
+ private static final InetAddress PCSCFV4 = InetAddresses.parseNumericAddress("10.77.25.37");
+ private static final InetAddress PCSCFV6 = InetAddresses.parseNumericAddress(
"2001:0db8:85a3:0000:0000:8a2e:0370:1");
- private static InetAddress GATEWAY1 = NetworkUtils.numericToInetAddress("75.208.8.1");
- private static InetAddress GATEWAY2 = NetworkUtils.numericToInetAddress("69.78.8.1");
- private static InetAddress GATEWAY61 = NetworkUtils.numericToInetAddress("fe80::6:0000:613");
- private static InetAddress GATEWAY62 = NetworkUtils.numericToInetAddress("fe80::6:2222");
- private static String NAME = "qmi0";
- private static int MTU = 1500;
-
- private static LinkAddress LINKADDRV4 = new LinkAddress(ADDRV4, 32);
- private static LinkAddress LINKADDRV6 = new LinkAddress(ADDRV6, 128);
- private static LinkAddress LINKADDRV6LINKLOCAL = new LinkAddress("fe80::1/64");
+ private static final InetAddress GATEWAY1 = InetAddresses.parseNumericAddress("75.208.8.1");
+ private static final InetAddress GATEWAY2 = InetAddresses.parseNumericAddress("69.78.8.1");
+ private static final InetAddress GATEWAY61 = InetAddresses.parseNumericAddress(
+ "fe80::6:0000:613");
+ private static final InetAddress GATEWAY62 = InetAddresses.parseNumericAddress("fe80::6:2222");
+ private static final String NAME = "qmi0";
+ private static final String DOMAINS = "google.com";
+ private static final String PRIV_DNS_SERVER_NAME = "private.dns.com";
+ private static final String TCP_BUFFER_SIZES = "524288,1048576,2097152,262144,524288,1048576";
+ private static final int MTU = 1500;
+ private static final LinkAddress LINKADDRV4 = new LinkAddress(ADDRV4, 32);
+ private static final LinkAddress LINKADDRV6 = new LinkAddress(ADDRV6, 128);
+ private static final LinkAddress LINKADDRV6LINKLOCAL = new LinkAddress("fe80::1/64");
// TODO: replace all calls to NetworkUtils.numericToInetAddress with calls to this method.
private InetAddress Address(String addrString) {
- return NetworkUtils.numericToInetAddress(addrString);
+ return InetAddresses.parseNumericAddress(addrString);
+ }
+
+ private void checkEmpty(final LinkProperties lp) {
+ assertEquals(0, lp.getAllInterfaceNames().size());
+ assertEquals(0, lp.getAllAddresses().size());
+ assertEquals(0, lp.getDnsServers().size());
+ assertEquals(0, lp.getValidatedPrivateDnsServers().size());
+ assertEquals(0, lp.getPcscfServers().size());
+ assertEquals(0, lp.getAllRoutes().size());
+ assertEquals(0, lp.getAllLinkAddresses().size());
+ assertEquals(0, lp.getStackedLinks().size());
+ assertEquals(0, lp.getMtu());
+ assertNull(lp.getPrivateDnsServerName());
+ assertNull(lp.getDomains());
+ assertNull(lp.getHttpProxy());
+ assertNull(lp.getTcpBufferSizes());
+ assertNull(lp.getNat64Prefix());
+ assertFalse(lp.isProvisioned());
+ assertFalse(lp.isIpv4Provisioned());
+ assertFalse(lp.isIpv6Provisioned());
+ assertFalse(lp.isPrivateDnsActive());
+ }
+
+ private LinkProperties makeTestObject() {
+ final LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName(NAME);
+ lp.addLinkAddress(LINKADDRV4);
+ lp.addLinkAddress(LINKADDRV6);
+ lp.addDnsServer(DNS1);
+ lp.addDnsServer(DNS2);
+ lp.addValidatedPrivateDnsServer(PRIVDNS1);
+ lp.addValidatedPrivateDnsServer(PRIVDNS2);
+ lp.setUsePrivateDns(true);
+ lp.setPrivateDnsServerName(PRIV_DNS_SERVER_NAME);
+ lp.addPcscfServer(PCSCFV6);
+ lp.setDomains(DOMAINS);
+ lp.addRoute(new RouteInfo(GATEWAY1));
+ lp.addRoute(new RouteInfo(GATEWAY2));
+ lp.setHttpProxy(ProxyInfo.buildDirectProxy("test", 8888));
+ lp.setMtu(MTU);
+ lp.setTcpBufferSizes(TCP_BUFFER_SIZES);
+ lp.setNat64Prefix(new IpPrefix("2001:db8:0:64::/96"));
+ return lp;
}
public void assertLinkPropertiesEqual(LinkProperties source, LinkProperties target) {
@@ -170,8 +223,7 @@
target.clear();
target.setInterfaceName(NAME);
// change link addresses
- target.addLinkAddress(new LinkAddress(
- NetworkUtils.numericToInetAddress("75.208.6.2"), 32));
+ target.addLinkAddress(new LinkAddress(Address("75.208.6.2"), 32));
target.addLinkAddress(LINKADDRV6);
target.addDnsServer(DNS1);
target.addDnsServer(DNS2);
@@ -186,7 +238,7 @@
target.addLinkAddress(LINKADDRV4);
target.addLinkAddress(LINKADDRV6);
// change dnses
- target.addDnsServer(NetworkUtils.numericToInetAddress("75.208.7.2"));
+ target.addDnsServer(Address("75.208.7.2"));
target.addDnsServer(DNS2);
target.addPcscfServer(PCSCFV6);
target.addRoute(new RouteInfo(GATEWAY1));
@@ -198,11 +250,10 @@
target.setInterfaceName(NAME);
target.addLinkAddress(LINKADDRV4);
target.addLinkAddress(LINKADDRV6);
- target.addDnsServer(NetworkUtils.numericToInetAddress("75.208.7.2"));
+ target.addDnsServer(Address("75.208.7.2"));
target.addDnsServer(DNS2);
// change pcscf
- target.addPcscfServer(NetworkUtils.numericToInetAddress(
- "2001::1"));
+ target.addPcscfServer(Address("2001::1"));
target.addRoute(new RouteInfo(GATEWAY1));
target.addRoute(new RouteInfo(GATEWAY2));
target.setMtu(MTU);
@@ -215,7 +266,7 @@
target.addDnsServer(DNS1);
target.addDnsServer(DNS2);
// change gateway
- target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress("75.208.8.2")));
+ target.addRoute(new RouteInfo(Address("75.208.8.2")));
target.addRoute(new RouteInfo(GATEWAY2));
target.setMtu(MTU);
assertFalse(source.equals(target));
@@ -285,10 +336,15 @@
}
}
+ private void assertAllRoutesNotHaveInterface(String iface, LinkProperties lp) {
+ for (RouteInfo r : lp.getRoutes()) {
+ assertNotEquals(iface, r.getInterface());
+ }
+ }
+
@Test
public void testRouteInterfaces() {
- LinkAddress prefix = new LinkAddress(
- NetworkUtils.numericToInetAddress("2001:db8::"), 32);
+ LinkAddress prefix = new LinkAddress(Address("2001:db8::"), 32);
InetAddress address = ADDRV6;
// Add a route with no interface to a LinkProperties with no interface. No errors.
@@ -312,6 +368,8 @@
// Change the interface name. All the routes should change their interface name too.
lp.setInterfaceName("rmnet0");
assertAllRoutesHaveInterface("rmnet0", lp);
+ assertAllRoutesNotHaveInterface(null, lp);
+ assertAllRoutesNotHaveInterface("wlan0", lp);
// Now add a route with the wrong interface. This causes an exception too.
try {
@@ -325,6 +383,7 @@
lp.addRoute(r);
assertEquals(2, lp.getRoutes().size());
assertAllRoutesHaveInterface("wlan0", lp);
+ assertAllRoutesNotHaveInterface("rmnet0", lp);
// Routes with null interfaces are converted to wlan0.
r = RouteInfo.makeHostRoute(ADDRV6, null);
@@ -334,14 +393,23 @@
// Check comparisons work.
LinkProperties lp2 = new LinkProperties(lp);
- assertAllRoutesHaveInterface("wlan0", lp);
+ assertAllRoutesHaveInterface("wlan0", lp2);
assertEquals(0, lp.compareAllRoutes(lp2).added.size());
assertEquals(0, lp.compareAllRoutes(lp2).removed.size());
lp2.setInterfaceName("p2p0");
assertAllRoutesHaveInterface("p2p0", lp2);
+ assertAllRoutesNotHaveInterface("wlan0", lp2);
assertEquals(3, lp.compareAllRoutes(lp2).added.size());
assertEquals(3, lp.compareAllRoutes(lp2).removed.size());
+
+ // Check remove works
+ lp.removeRoute(new RouteInfo(prefix, address, null));
+ assertEquals(3, lp.getRoutes().size());
+ lp.removeRoute(new RouteInfo(prefix, address, "wlan0"));
+ assertEquals(2, lp.getRoutes().size());
+ assertAllRoutesHaveInterface("wlan0", lp);
+ assertAllRoutesNotHaveInterface("p2p0", lp);
}
@Test
@@ -488,18 +556,26 @@
}
@Test
- public void testSetLinkAddresses() {
- LinkProperties lp = new LinkProperties();
+ public void testLinkAddresses() {
+ final LinkProperties lp = new LinkProperties();
lp.addLinkAddress(LINKADDRV4);
lp.addLinkAddress(LINKADDRV6);
- LinkProperties lp2 = new LinkProperties();
+ final LinkProperties lp2 = new LinkProperties();
lp2.addLinkAddress(LINKADDRV6);
- assertFalse(lp.equals(lp2));
+ final LinkProperties lp3 = new LinkProperties();
+ final List<LinkAddress> linkAddresses = Arrays.asList(LINKADDRV4);
+ lp3.setLinkAddresses(linkAddresses);
- lp2.setLinkAddresses(lp.getLinkAddresses());
- assertTrue(lp.equals(lp));
+ assertFalse(lp.equals(lp2));
+ assertFalse(lp2.equals(lp3));
+
+ lp.removeLinkAddress(LINKADDRV4);
+ assertTrue(lp.equals(lp2));
+
+ lp2.setLinkAddresses(lp3.getLinkAddresses());
+ assertTrue(lp2.equals(lp3));
}
@Test
@@ -675,9 +751,9 @@
assertTrue(v4lp.isReachable(DNS2));
final LinkProperties v6lp = new LinkProperties();
- final InetAddress kLinkLocalDns = NetworkUtils.numericToInetAddress("fe80::6:1");
- final InetAddress kLinkLocalDnsWithScope = NetworkUtils.numericToInetAddress("fe80::6:2%43");
- final InetAddress kOnLinkDns = NetworkUtils.numericToInetAddress("2001:db8:85a3::53");
+ final InetAddress kLinkLocalDns = Address("fe80::6:1");
+ final InetAddress kLinkLocalDnsWithScope = Address("fe80::6:2%43");
+ final InetAddress kOnLinkDns = Address("2001:db8:85a3::53");
assertFalse(v6lp.isReachable(kLinkLocalDns));
assertFalse(v6lp.isReachable(kLinkLocalDnsWithScope));
assertFalse(v6lp.isReachable(kOnLinkDns));
@@ -686,8 +762,7 @@
// Add a link-local route, making the link-local DNS servers reachable. Because
// we assume the presence of an IPv6 link-local address, link-local DNS servers
// are considered reachable, but only those with a non-zero scope identifier.
- assertTrue(v6lp.addRoute(new RouteInfo(
- new IpPrefix(NetworkUtils.numericToInetAddress("fe80::"), 64))));
+ assertTrue(v6lp.addRoute(new RouteInfo(new IpPrefix(Address("fe80::"), 64))));
assertFalse(v6lp.isReachable(kLinkLocalDns));
assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
assertFalse(v6lp.isReachable(kOnLinkDns));
@@ -703,8 +778,7 @@
// Add a global route on link, but no global address yet. DNS servers reachable
// via a route that doesn't require a gateway: give them the benefit of the
// doubt and hope the link-local source address suffices for communication.
- assertTrue(v6lp.addRoute(new RouteInfo(
- new IpPrefix(NetworkUtils.numericToInetAddress("2001:db8:85a3::"), 64))));
+ assertTrue(v6lp.addRoute(new RouteInfo(new IpPrefix(Address("2001:db8:85a3::"), 64))));
assertFalse(v6lp.isReachable(kLinkLocalDns));
assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
assertTrue(v6lp.isReachable(kOnLinkDns));
@@ -766,8 +840,8 @@
LinkProperties rmnet1 = new LinkProperties();
rmnet1.setInterfaceName("rmnet1");
rmnet1.addLinkAddress(new LinkAddress("10.0.0.3/8"));
- RouteInfo defaultRoute1 = new RouteInfo((IpPrefix) null,
- NetworkUtils.numericToInetAddress("10.0.0.1"), rmnet1.getInterfaceName());
+ RouteInfo defaultRoute1 = new RouteInfo((IpPrefix) null, Address("10.0.0.1"),
+ rmnet1.getInterfaceName());
RouteInfo directRoute1 = new RouteInfo(new IpPrefix("10.0.0.0/8"), null,
rmnet1.getInterfaceName());
rmnet1.addRoute(defaultRoute1);
@@ -785,8 +859,8 @@
rmnet2.setInterfaceName("rmnet2");
rmnet2.addLinkAddress(new LinkAddress("fe80::cafe/64"));
rmnet2.addLinkAddress(new LinkAddress("2001:db8::2/64"));
- RouteInfo defaultRoute2 = new RouteInfo((IpPrefix) null,
- NetworkUtils.numericToInetAddress("2001:db8::1"), rmnet2.getInterfaceName());
+ RouteInfo defaultRoute2 = new RouteInfo((IpPrefix) null, Address("2001:db8::1"),
+ rmnet2.getInterfaceName());
RouteInfo directRoute2 = new RouteInfo(new IpPrefix("2001:db8::/64"), null,
rmnet2.getInterfaceName());
RouteInfo linkLocalRoute2 = new RouteInfo(new IpPrefix("fe80::/64"), null,
@@ -868,12 +942,119 @@
source.setNat64Prefix(new IpPrefix("2001:db8:1:2:64:64::/96"));
- TestUtils.assertParcelingIsLossless(source, LinkProperties.CREATOR);
+ assertParcelingIsLossless(source);
}
@Test
public void testParcelUninitialized() throws Exception {
LinkProperties empty = new LinkProperties();
- TestUtils.assertParcelingIsLossless(empty, LinkProperties.CREATOR);
+ assertParcelingIsLossless(empty);
+ }
+
+ @Test
+ public void testConstructor() {
+ LinkProperties lp = new LinkProperties();
+ checkEmpty(lp);
+ assertLinkPropertiesEqual(lp, new LinkProperties(lp));
+ assertLinkPropertiesEqual(lp, new LinkProperties());
+
+ lp = makeTestObject();
+ assertLinkPropertiesEqual(lp, new LinkProperties(lp));
+ }
+
+ @Test
+ public void testDnsServers() {
+ final LinkProperties lp = new LinkProperties();
+ final List<InetAddress> dnsServers = Arrays.asList(DNS1, DNS2);
+ lp.setDnsServers(dnsServers);
+ assertEquals(2, lp.getDnsServers().size());
+ assertEquals(DNS1, lp.getDnsServers().get(0));
+ assertEquals(DNS2, lp.getDnsServers().get(1));
+
+ lp.removeDnsServer(DNS1);
+ assertEquals(1, lp.getDnsServers().size());
+ assertEquals(DNS2, lp.getDnsServers().get(0));
+
+ lp.addDnsServer(DNS6);
+ assertEquals(2, lp.getDnsServers().size());
+ assertEquals(DNS2, lp.getDnsServers().get(0));
+ assertEquals(DNS6, lp.getDnsServers().get(1));
+ }
+
+ @Test
+ public void testValidatedPrivateDnsServers() {
+ final LinkProperties lp = new LinkProperties();
+ final List<InetAddress> privDnsServers = Arrays.asList(PRIVDNS1, PRIVDNS2);
+ lp.setValidatedPrivateDnsServers(privDnsServers);
+ assertEquals(2, lp.getValidatedPrivateDnsServers().size());
+ assertEquals(PRIVDNS1, lp.getValidatedPrivateDnsServers().get(0));
+ assertEquals(PRIVDNS2, lp.getValidatedPrivateDnsServers().get(1));
+
+ lp.removeValidatedPrivateDnsServer(PRIVDNS1);
+ assertEquals(1, lp.getValidatedPrivateDnsServers().size());
+ assertEquals(PRIVDNS2, lp.getValidatedPrivateDnsServers().get(0));
+
+ lp.addValidatedPrivateDnsServer(PRIVDNS6);
+ assertEquals(2, lp.getValidatedPrivateDnsServers().size());
+ assertEquals(PRIVDNS2, lp.getValidatedPrivateDnsServers().get(0));
+ assertEquals(PRIVDNS6, lp.getValidatedPrivateDnsServers().get(1));
+ }
+
+ @Test
+ public void testPcscfServers() {
+ final LinkProperties lp = new LinkProperties();
+ final List<InetAddress> pcscfServers = Arrays.asList(PCSCFV4);
+ lp.setPcscfServers(pcscfServers);
+ assertEquals(1, lp.getPcscfServers().size());
+ assertEquals(PCSCFV4, lp.getPcscfServers().get(0));
+
+ lp.removePcscfServer(PCSCFV4);
+ assertEquals(0, lp.getPcscfServers().size());
+
+ lp.addPcscfServer(PCSCFV6);
+ assertEquals(1, lp.getPcscfServers().size());
+ assertEquals(PCSCFV6, lp.getPcscfServers().get(0));
+ }
+
+ @Test
+ public void testTcpBufferSizes() {
+ final LinkProperties lp = makeTestObject();
+ assertEquals(TCP_BUFFER_SIZES, lp.getTcpBufferSizes());
+
+ lp.setTcpBufferSizes(null);
+ assertNull(lp.getTcpBufferSizes());
+ }
+
+ @Test
+ public void testHasIpv6DefaultRoute() {
+ final LinkProperties lp = makeTestObject();
+ assertFalse(lp.hasIPv6DefaultRoute());
+
+ lp.addRoute(new RouteInfo(GATEWAY61));
+ assertTrue(lp.hasIPv6DefaultRoute());
+ }
+
+ @Test
+ public void testHttpProxy() {
+ final LinkProperties lp = makeTestObject();
+ assertTrue(lp.getHttpProxy().equals(ProxyInfo.buildDirectProxy("test", 8888)));
+ }
+
+ @Test
+ public void testPrivateDnsServerName() {
+ final LinkProperties lp = makeTestObject();
+ assertEquals(PRIV_DNS_SERVER_NAME, lp.getPrivateDnsServerName());
+
+ lp.setPrivateDnsServerName(null);
+ assertNull(lp.getPrivateDnsServerName());
+ }
+
+ @Test
+ public void testUsePrivateDns() {
+ final LinkProperties lp = makeTestObject();
+ assertTrue(lp.isPrivateDnsActive());
+
+ lp.clear();
+ assertFalse(lp.isPrivateDnsActive());
}
}
diff --git a/tests/net/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
similarity index 95%
rename from tests/net/java/android/net/NetworkCapabilitiesTest.java
rename to tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index ad76388..2ca0d1a 100644
--- a/tests/net/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -33,9 +33,14 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
import static android.net.NetworkCapabilities.RESTRICTED_CAPABILITIES;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_TEST;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkCapabilities.UNRESTRICTED_CAPABILITIES;
+import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
+import static com.android.testutils.ParcelUtilsKt.assertParcelingIsLossless;
+
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -43,7 +48,6 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import android.os.Parcel;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.ArraySet;
@@ -265,9 +269,9 @@
.setUids(uids)
.addCapability(NET_CAPABILITY_EIMS)
.addCapability(NET_CAPABILITY_NOT_METERED);
- assertEqualsThroughMarshalling(netCap);
+ assertParcelingIsLossless(netCap);
netCap.setSSID(TEST_SSID);
- assertEqualsThroughMarshalling(netCap);
+ assertParcelSane(netCap, 11);
}
@Test
@@ -540,18 +544,6 @@
nc1.combineCapabilities(nc3);
}
- private void assertEqualsThroughMarshalling(NetworkCapabilities netCap) {
- Parcel p = Parcel.obtain();
- netCap.writeToParcel(p, /* flags */ 0);
- p.setDataPosition(0);
- byte[] marshalledData = p.marshall();
-
- p = Parcel.obtain();
- p.unmarshall(marshalledData, 0, marshalledData.length);
- p.setDataPosition(0);
- assertEquals(NetworkCapabilities.CREATOR.createFromParcel(p), netCap);
- }
-
@Test
public void testSet() {
NetworkCapabilities nc1 = new NetworkCapabilities();
@@ -585,4 +577,20 @@
nc2.set(nc1); // Overwrites, as opposed to combineCapabilities
assertEquals(nc1, nc2);
}
+
+ @Test
+ public void testGetTransportTypes() {
+ final NetworkCapabilities nc = new NetworkCapabilities();
+ nc.addTransportType(TRANSPORT_CELLULAR);
+ nc.addTransportType(TRANSPORT_WIFI);
+ nc.addTransportType(TRANSPORT_VPN);
+ nc.addTransportType(TRANSPORT_TEST);
+
+ final int[] transportTypes = nc.getTransportTypes();
+ assertEquals(4, transportTypes.length);
+ assertEquals(TRANSPORT_CELLULAR, transportTypes[0]);
+ assertEquals(TRANSPORT_WIFI, transportTypes[1]);
+ assertEquals(TRANSPORT_VPN, transportTypes[2]);
+ assertEquals(TRANSPORT_TEST, transportTypes[3]);
+ }
}
diff --git a/tests/net/java/android/net/NetworkTest.java b/tests/net/common/java/android/net/NetworkTest.java
similarity index 75%
rename from tests/net/java/android/net/NetworkTest.java
rename to tests/net/common/java/android/net/NetworkTest.java
index 0bee7cd..11d44b8 100644
--- a/tests/net/java/android/net/NetworkTest.java
+++ b/tests/net/common/java/android/net/NetworkTest.java
@@ -18,13 +18,11 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import android.net.LocalServerSocket;
-import android.net.LocalSocket;
-import android.net.LocalSocketAddress;
-import android.net.Network;
+import android.platform.test.annotations.AppModeFull;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -39,7 +37,6 @@
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.SocketException;
-import java.util.Objects;
@RunWith(AndroidJUnit4.class)
@SmallTest
@@ -74,6 +71,7 @@
}
@Test
+ @AppModeFull(reason = "Socket cannot bind in instant app mode")
public void testBindSocketOfConnectedDatagramSocketThrows() throws Exception {
final DatagramSocket mDgramSocket = new DatagramSocket(0, (InetAddress) Inet6Address.ANY);
mDgramSocket.connect((InetAddress) Inet6Address.LOOPBACK, 53);
@@ -121,29 +119,29 @@
Network three = new Network(3);
// None of the hashcodes are zero.
- assertNotEqual(0, one.hashCode());
- assertNotEqual(0, two.hashCode());
- assertNotEqual(0, three.hashCode());
+ assertNotEquals(0, one.hashCode());
+ assertNotEquals(0, two.hashCode());
+ assertNotEquals(0, three.hashCode());
// All the hashcodes are distinct.
- assertNotEqual(one.hashCode(), two.hashCode());
- assertNotEqual(one.hashCode(), three.hashCode());
- assertNotEqual(two.hashCode(), three.hashCode());
+ assertNotEquals(one.hashCode(), two.hashCode());
+ assertNotEquals(one.hashCode(), three.hashCode());
+ assertNotEquals(two.hashCode(), three.hashCode());
// None of the handles are zero.
- assertNotEqual(0, one.getNetworkHandle());
- assertNotEqual(0, two.getNetworkHandle());
- assertNotEqual(0, three.getNetworkHandle());
+ assertNotEquals(0, one.getNetworkHandle());
+ assertNotEquals(0, two.getNetworkHandle());
+ assertNotEquals(0, three.getNetworkHandle());
// All the handles are distinct.
- assertNotEqual(one.getNetworkHandle(), two.getNetworkHandle());
- assertNotEqual(one.getNetworkHandle(), three.getNetworkHandle());
- assertNotEqual(two.getNetworkHandle(), three.getNetworkHandle());
+ assertNotEquals(one.getNetworkHandle(), two.getNetworkHandle());
+ assertNotEquals(one.getNetworkHandle(), three.getNetworkHandle());
+ assertNotEquals(two.getNetworkHandle(), three.getNetworkHandle());
// The handles are not equal to the hashcodes.
- assertNotEqual(one.hashCode(), one.getNetworkHandle());
- assertNotEqual(two.hashCode(), two.getNetworkHandle());
- assertNotEqual(three.hashCode(), three.getNetworkHandle());
+ assertNotEquals(one.hashCode(), one.getNetworkHandle());
+ assertNotEquals(two.hashCode(), two.getNetworkHandle());
+ assertNotEquals(three.hashCode(), three.getNetworkHandle());
// Adjust as necessary to test an implementation's specific constants.
// When running with runtest, "adb logcat -s TestRunner" can be useful.
@@ -152,7 +150,11 @@
assertEquals(16290598925L, three.getNetworkHandle());
}
- private static <T> void assertNotEqual(T t1, T t2) {
- assertFalse(Objects.equals(t1, t2));
+ @Test
+ public void testGetPrivateDnsBypassingCopy() {
+ final Network copy = mNetwork.getPrivateDnsBypassingCopy();
+ assertEquals(mNetwork.netId, copy.netId);
+ assertNotEquals(copy.netId, copy.getNetIdForResolv());
+ assertNotEquals(mNetwork.getNetIdForResolv(), copy.getNetIdForResolv());
}
}
diff --git a/tests/net/java/android/net/RouteInfoTest.java b/tests/net/common/java/android/net/RouteInfoTest.java
similarity index 89%
rename from tests/net/java/android/net/RouteInfoTest.java
rename to tests/net/common/java/android/net/RouteInfoTest.java
index 2edbd40..5ce8436 100644
--- a/tests/net/java/android/net/RouteInfoTest.java
+++ b/tests/net/common/java/android/net/RouteInfoTest.java
@@ -18,7 +18,11 @@
import static android.net.RouteInfo.RTN_UNREACHABLE;
-import android.os.Parcel;
+import static com.android.testutils.MiscAssertsKt.assertEqualBothWays;
+import static com.android.testutils.MiscAssertsKt.assertNotEqualEitherWay;
+import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
+import static com.android.testutils.ParcelUtilsKt.assertParcelingIsLossless;
+
import android.test.suitebuilder.annotation.SmallTest;
import junit.framework.TestCase;
@@ -109,47 +113,37 @@
assertFalse(ipv4Default.matches(Address("2001:db8::f00")));
}
- private void assertAreEqual(Object o1, Object o2) {
- assertTrue(o1.equals(o2));
- assertTrue(o2.equals(o1));
- }
-
- private void assertAreNotEqual(Object o1, Object o2) {
- assertFalse(o1.equals(o2));
- assertFalse(o2.equals(o1));
- }
-
public void testEquals() {
// IPv4
RouteInfo r1 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::1"), "wlan0");
RouteInfo r2 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::1"), "wlan0");
- assertAreEqual(r1, r2);
+ assertEqualBothWays(r1, r2);
RouteInfo r3 = new RouteInfo(Prefix("2001:db8:ace::/49"), Address("2001:db8::1"), "wlan0");
RouteInfo r4 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::2"), "wlan0");
RouteInfo r5 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::1"), "rmnet0");
- assertAreNotEqual(r1, r3);
- assertAreNotEqual(r1, r4);
- assertAreNotEqual(r1, r5);
+ assertNotEqualEitherWay(r1, r3);
+ assertNotEqualEitherWay(r1, r4);
+ assertNotEqualEitherWay(r1, r5);
// IPv6
r1 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), "wlan0");
r2 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), "wlan0");
- assertAreEqual(r1, r2);
+ assertEqualBothWays(r1, r2);
r3 = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0");
r4 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.2"), "wlan0");
r5 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), "rmnet0");
- assertAreNotEqual(r1, r3);
- assertAreNotEqual(r1, r4);
- assertAreNotEqual(r1, r5);
+ assertNotEqualEitherWay(r1, r3);
+ assertNotEqualEitherWay(r1, r4);
+ assertNotEqualEitherWay(r1, r5);
// Interfaces (but not destinations or gateways) can be null.
r1 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), null);
r2 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), null);
r3 = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0");
- assertAreEqual(r1, r2);
- assertAreNotEqual(r1, r3);
+ assertEqualBothWays(r1, r2);
+ assertNotEqualEitherWay(r1, r3);
}
public void testHostAndDefaultRoutes() {
@@ -257,25 +251,6 @@
// No exceptions? Good.
}
- public RouteInfo passThroughParcel(RouteInfo r) {
- Parcel p = Parcel.obtain();
- RouteInfo r2 = null;
- try {
- r.writeToParcel(p, 0);
- p.setDataPosition(0);
- r2 = RouteInfo.CREATOR.createFromParcel(p);
- } finally {
- p.recycle();
- }
- assertNotNull(r2);
- return r2;
- }
-
- public void assertParcelingIsLossless(RouteInfo r) {
- RouteInfo r2 = passThroughParcel(r);
- assertEquals(r, r2);
- }
-
public void testParceling() {
RouteInfo r;
@@ -283,6 +258,6 @@
assertParcelingIsLossless(r);
r = new RouteInfo(Prefix("192.0.2.0/24"), null, "wlan0");
- assertParcelingIsLossless(r);
+ assertParcelSane(r, 6);
}
}
diff --git a/tests/net/java/android/net/StaticIpConfigurationTest.java b/tests/net/common/java/android/net/StaticIpConfigurationTest.java
similarity index 77%
rename from tests/net/java/android/net/StaticIpConfigurationTest.java
rename to tests/net/common/java/android/net/StaticIpConfigurationTest.java
index 8449ca7..b5f23bf 100644
--- a/tests/net/java/android/net/StaticIpConfigurationTest.java
+++ b/tests/net/common/java/android/net/StaticIpConfigurationTest.java
@@ -18,6 +18,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -31,8 +32,9 @@
import org.junit.runner.RunWith;
import java.net.InetAddress;
+import java.util.ArrayList;
import java.util.HashSet;
-import java.util.Objects;
+import java.util.List;
@RunWith(AndroidJUnit4.class)
@SmallTest
@@ -46,6 +48,7 @@
private static final InetAddress DNS2 = IpAddress("8.8.4.4");
private static final InetAddress DNS3 = IpAddress("4.2.2.2");
private static final String IFACE = "eth0";
+ private static final String FAKE_DOMAINS = "google.com";
private static InetAddress IpAddress(String addr) {
return InetAddress.parseNumericAddress(addr);
@@ -58,10 +61,6 @@
assertEquals(0, s.dnsServers.size());
}
- private static <T> void assertNotEquals(T t1, T t2) {
- assertFalse(Objects.equals(t1, t2));
- }
-
private StaticIpConfiguration makeTestObject() {
StaticIpConfiguration s = new StaticIpConfiguration();
s.ipAddress = ADDR;
@@ -69,7 +68,7 @@
s.dnsServers.add(DNS1);
s.dnsServers.add(DNS2);
s.dnsServers.add(DNS3);
- s.domains = "google.com";
+ s.domains = FAKE_DOMAINS;
return s;
}
@@ -178,8 +177,8 @@
expected.addDnsServer(DNS3);
assertEquals(expected, s.toLinkProperties(IFACE));
- s.domains = "google.com";
- expected.setDomains("google.com");
+ s.domains = FAKE_DOMAINS;
+ expected.setDomains(FAKE_DOMAINS);
assertEquals(expected, s.toLinkProperties(IFACE));
s.gateway = null;
@@ -218,4 +217,53 @@
StaticIpConfiguration s2 = passThroughParcel(s);
assertEquals(s, s2);
}
+
+ @Test
+ public void testBuilder() {
+ final ArrayList<InetAddress> dnsServers = new ArrayList<>();
+ dnsServers.add(DNS1);
+
+ final StaticIpConfiguration s = new StaticIpConfiguration.Builder()
+ .setIpAddress(ADDR)
+ .setGateway(GATEWAY)
+ .setDomains(FAKE_DOMAINS)
+ .setDnsServers(dnsServers)
+ .build();
+
+ assertEquals(s.ipAddress, s.getIpAddress());
+ assertEquals(ADDR, s.getIpAddress());
+ assertEquals(s.gateway, s.getGateway());
+ assertEquals(GATEWAY, s.getGateway());
+ assertEquals(s.domains, s.getDomains());
+ assertEquals(FAKE_DOMAINS, s.getDomains());
+ assertTrue(s.dnsServers.equals(s.getDnsServers()));
+ assertEquals(1, s.getDnsServers().size());
+ assertEquals(DNS1, s.getDnsServers().get(0));
+ }
+
+ @Test
+ public void testAddDnsServers() {
+ final StaticIpConfiguration s = new StaticIpConfiguration((StaticIpConfiguration) null);
+ checkEmpty(s);
+
+ s.addDnsServer(DNS1);
+ assertEquals(1, s.getDnsServers().size());
+ assertEquals(DNS1, s.getDnsServers().get(0));
+
+ s.addDnsServer(DNS2);
+ s.addDnsServer(DNS3);
+ assertEquals(3, s.getDnsServers().size());
+ assertEquals(DNS2, s.getDnsServers().get(1));
+ assertEquals(DNS3, s.getDnsServers().get(2));
+ }
+
+ @Test
+ public void testGetRoutes() {
+ final StaticIpConfiguration s = makeTestObject();
+ final List<RouteInfo> routeInfoList = s.getRoutes(IFACE);
+
+ assertEquals(2, routeInfoList.size());
+ assertEquals(new RouteInfo(ADDR, (InetAddress) null, IFACE), routeInfoList.get(0));
+ assertEquals(new RouteInfo((IpPrefix) null, GATEWAY, IFACE), routeInfoList.get(1));
+ }
}
diff --git a/tests/net/java/android/net/apf/ApfCapabilitiesTest.java b/tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java
similarity index 65%
rename from tests/net/java/android/net/apf/ApfCapabilitiesTest.java
rename to tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java
index 75752c3..f4f804a 100644
--- a/tests/net/java/android/net/apf/ApfCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java
@@ -16,16 +16,16 @@
package android.net.apf;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
+import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
-import android.net.shared.ParcelableTestUtil;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.internal.util.TestUtils;
-
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -33,11 +33,13 @@
@SmallTest
public class ApfCapabilitiesTest {
@Test
- public void testParcelUnparcel() {
+ public void testConstructAndParcel() {
final ApfCapabilities caps = new ApfCapabilities(123, 456, 789);
- ParcelableTestUtil.assertFieldCountEquals(3, ApfCapabilities.class);
+ assertEquals(123, caps.apfVersionSupported);
+ assertEquals(456, caps.maximumApfProgramSize);
+ assertEquals(789, caps.apfPacketFormat);
- TestUtils.assertParcelingIsLossless(caps, ApfCapabilities.CREATOR);
+ assertParcelSane(caps, 3);
}
@Test
@@ -47,4 +49,14 @@
assertNotEquals(new ApfCapabilities(1, 3, 3), new ApfCapabilities(1, 2, 3));
assertNotEquals(new ApfCapabilities(1, 2, 4), new ApfCapabilities(1, 2, 3));
}
+
+ @Test
+ public void testHasDataAccess() {
+ //hasDataAccess is only supported starting at apf version 4.
+ ApfCapabilities caps = new ApfCapabilities(1 /* apfVersionSupported */, 2, 3);
+ assertFalse(caps.hasDataAccess());
+
+ caps = new ApfCapabilities(4 /* apfVersionSupported */, 5, 6);
+ assertTrue(caps.hasDataAccess());
+ }
}
diff --git a/tests/net/common/java/android/net/metrics/ApfProgramEventTest.kt b/tests/net/common/java/android/net/metrics/ApfProgramEventTest.kt
new file mode 100644
index 0000000..0b7b740
--- /dev/null
+++ b/tests/net/common/java/android/net/metrics/ApfProgramEventTest.kt
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+package android.net.metrics;
+
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.testutils.assertParcelSane
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class ApfProgramEventTest {
+ private infix fun Int.hasFlag(flag: Int) = (this and (1 shl flag)) != 0
+
+ @Test
+ fun testBuilderAndParcel() {
+ val apfProgramEvent = ApfProgramEvent.Builder()
+ .setLifetime(1)
+ .setActualLifetime(2)
+ .setFilteredRas(3)
+ .setCurrentRas(4)
+ .setProgramLength(5)
+ .setFlags(true, true)
+ .build()
+
+ assertEquals(1, apfProgramEvent.lifetime)
+ assertEquals(2, apfProgramEvent.actualLifetime)
+ assertEquals(3, apfProgramEvent.filteredRas)
+ assertEquals(4, apfProgramEvent.currentRas)
+ assertEquals(5, apfProgramEvent.programLength)
+ assertEquals(ApfProgramEvent.flagsFor(true, true), apfProgramEvent.flags)
+
+ assertParcelSane(apfProgramEvent, 6)
+ }
+
+ @Test
+ fun testFlagsFor() {
+ var flags = ApfProgramEvent.flagsFor(false, false)
+ assertFalse(flags hasFlag ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS)
+ assertFalse(flags hasFlag ApfProgramEvent.FLAG_MULTICAST_FILTER_ON)
+
+ flags = ApfProgramEvent.flagsFor(true, false)
+ assertTrue(flags hasFlag ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS)
+ assertFalse(flags hasFlag ApfProgramEvent.FLAG_MULTICAST_FILTER_ON)
+
+ flags = ApfProgramEvent.flagsFor(false, true)
+ assertFalse(flags hasFlag ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS)
+ assertTrue(flags hasFlag ApfProgramEvent.FLAG_MULTICAST_FILTER_ON)
+
+ flags = ApfProgramEvent.flagsFor(true, true)
+ assertTrue(flags hasFlag ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS)
+ assertTrue(flags hasFlag ApfProgramEvent.FLAG_MULTICAST_FILTER_ON)
+ }
+}
diff --git a/tests/net/common/java/android/net/metrics/ApfStatsTest.kt b/tests/net/common/java/android/net/metrics/ApfStatsTest.kt
new file mode 100644
index 0000000..46a8c8e
--- /dev/null
+++ b/tests/net/common/java/android/net/metrics/ApfStatsTest.kt
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+package android.net.metrics
+
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.testutils.assertParcelSane
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class ApfStatsTest {
+ @Test
+ fun testBuilderAndParcel() {
+ val apfStats = ApfStats.Builder()
+ .setDurationMs(Long.MAX_VALUE)
+ .setReceivedRas(1)
+ .setMatchingRas(2)
+ .setDroppedRas(3)
+ .setZeroLifetimeRas(4)
+ .setParseErrors(5)
+ .setProgramUpdates(6)
+ .setProgramUpdatesAll(7)
+ .setProgramUpdatesAllowingMulticast(8)
+ .setMaxProgramSize(9)
+ .build()
+
+ assertEquals(Long.MAX_VALUE, apfStats.durationMs)
+ assertEquals(1, apfStats.receivedRas)
+ assertEquals(2, apfStats.matchingRas)
+ assertEquals(3, apfStats.droppedRas)
+ assertEquals(4, apfStats.zeroLifetimeRas)
+ assertEquals(5, apfStats.parseErrors)
+ assertEquals(6, apfStats.programUpdates)
+ assertEquals(7, apfStats.programUpdatesAll)
+ assertEquals(8, apfStats.programUpdatesAllowingMulticast)
+ assertEquals(9, apfStats.maxProgramSize)
+
+ assertParcelSane(apfStats, 10)
+ }
+}
diff --git a/tests/net/common/java/android/net/metrics/DhcpErrorEventTest.kt b/tests/net/common/java/android/net/metrics/DhcpErrorEventTest.kt
new file mode 100644
index 0000000..236f72e
--- /dev/null
+++ b/tests/net/common/java/android/net/metrics/DhcpErrorEventTest.kt
@@ -0,0 +1,65 @@
+package android.net.metrics
+
+import android.net.metrics.DhcpErrorEvent.DHCP_INVALID_OPTION_LENGTH
+import android.net.metrics.DhcpErrorEvent.errorCodeWithOption
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.testutils.parcelingRoundTrip
+import java.lang.reflect.Modifier
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNotNull
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private const val TEST_ERROR_CODE = 12345
+//DHCP Optional Type: DHCP Subnet Mask (Copy from DhcpPacket.java due to it's protected)
+private const val DHCP_SUBNET_MASK = 1
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class DhcpErrorEventTest {
+
+ @Test
+ fun testConstructor() {
+ val event = DhcpErrorEvent(TEST_ERROR_CODE)
+ assertEquals(TEST_ERROR_CODE, event.errorCode)
+ }
+
+ @Test
+ fun testParcelUnparcel() {
+ val event = DhcpErrorEvent(TEST_ERROR_CODE)
+ val parceled = parcelingRoundTrip(event)
+ assertEquals(TEST_ERROR_CODE, parceled.errorCode)
+ }
+
+ @Test
+ fun testErrorCodeWithOption() {
+ val errorCode = errorCodeWithOption(DHCP_INVALID_OPTION_LENGTH, DHCP_SUBNET_MASK);
+ assertTrue((DHCP_INVALID_OPTION_LENGTH and errorCode) == DHCP_INVALID_OPTION_LENGTH);
+ assertTrue((DHCP_SUBNET_MASK and errorCode) == DHCP_SUBNET_MASK);
+ }
+
+ @Test
+ fun testToString() {
+ val names = listOf("L2_ERROR", "L3_ERROR", "L4_ERROR", "DHCP_ERROR", "MISC_ERROR")
+ val errorFields = DhcpErrorEvent::class.java.declaredFields.filter {
+ it.type == Int::class.javaPrimitiveType
+ && Modifier.isPublic(it.modifiers) && Modifier.isStatic(it.modifiers)
+ && it.name !in names
+ }
+
+ errorFields.forEach {
+ val intValue = it.getInt(null)
+ val stringValue = DhcpErrorEvent(intValue).toString()
+ assertTrue("Invalid string for error 0x%08X (field %s): %s".format(intValue, it.name,
+ stringValue),
+ stringValue.contains(it.name))
+ }
+ }
+
+ @Test
+ fun testToString_InvalidErrorCode() {
+ assertNotNull(DhcpErrorEvent(TEST_ERROR_CODE).toString())
+ }
+}
diff --git a/tests/net/common/java/android/net/metrics/IpConnectivityLogTest.java b/tests/net/common/java/android/net/metrics/IpConnectivityLogTest.java
new file mode 100644
index 0000000..d4780d3
--- /dev/null
+++ b/tests/net/common/java/android/net/metrics/IpConnectivityLogTest.java
@@ -0,0 +1,161 @@
+/*
+ * 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.
+ */
+
+package android.net.metrics;
+
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+
+import android.net.ConnectivityMetricsEvent;
+import android.net.IIpConnectivityMetrics;
+import android.net.Network;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.BitUtils;
+
+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 java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class IpConnectivityLogTest {
+ private static final int FAKE_NET_ID = 100;
+ private static final int[] FAKE_TRANSPORT_TYPES = BitUtils.unpackBits(TRANSPORT_WIFI);
+ private static final long FAKE_TIME_STAMP = System.currentTimeMillis();
+ private static final String FAKE_INTERFACE_NAME = "test";
+ private static final IpReachabilityEvent FAKE_EV =
+ new IpReachabilityEvent(IpReachabilityEvent.NUD_FAILED);
+
+ @Mock IIpConnectivityMetrics mMockService;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void testLoggingEvents() throws Exception {
+ IpConnectivityLog logger = new IpConnectivityLog(mMockService);
+
+ assertTrue(logger.log(FAKE_EV));
+ assertTrue(logger.log(FAKE_TIME_STAMP, FAKE_EV));
+ assertTrue(logger.log(FAKE_NET_ID, FAKE_TRANSPORT_TYPES, FAKE_EV));
+ assertTrue(logger.log(new Network(FAKE_NET_ID), FAKE_TRANSPORT_TYPES, FAKE_EV));
+ assertTrue(logger.log(FAKE_INTERFACE_NAME, FAKE_EV));
+ assertTrue(logger.log(makeExpectedEvent(FAKE_TIME_STAMP, FAKE_NET_ID, TRANSPORT_WIFI,
+ FAKE_INTERFACE_NAME)));
+
+ List<ConnectivityMetricsEvent> got = verifyEvents(6);
+ assertEventsEqual(makeExpectedEvent(got.get(0).timestamp, 0, 0, null), got.get(0));
+ assertEventsEqual(makeExpectedEvent(FAKE_TIME_STAMP, 0, 0, null), got.get(1));
+ assertEventsEqual(makeExpectedEvent(got.get(2).timestamp, FAKE_NET_ID,
+ TRANSPORT_WIFI, null), got.get(2));
+ assertEventsEqual(makeExpectedEvent(got.get(3).timestamp, FAKE_NET_ID,
+ TRANSPORT_WIFI, null), got.get(3));
+ assertEventsEqual(makeExpectedEvent(got.get(4).timestamp, 0, 0, FAKE_INTERFACE_NAME),
+ got.get(4));
+ assertEventsEqual(makeExpectedEvent(FAKE_TIME_STAMP, FAKE_NET_ID,
+ TRANSPORT_WIFI, FAKE_INTERFACE_NAME), got.get(5));
+ }
+
+ @Test
+ public void testLoggingEventsWithMultipleCallers() throws Exception {
+ IpConnectivityLog logger = new IpConnectivityLog(mMockService);
+
+ final int nCallers = 10;
+ final int nEvents = 10;
+ for (int n = 0; n < nCallers; n++) {
+ final int i = n;
+ new Thread() {
+ public void run() {
+ for (int j = 0; j < nEvents; j++) {
+ assertTrue(logger.log(makeExpectedEvent(
+ FAKE_TIME_STAMP + i * 100 + j,
+ FAKE_NET_ID + i * 100 + j,
+ ((i + j) % 2 == 0) ? TRANSPORT_WIFI : TRANSPORT_CELLULAR,
+ FAKE_INTERFACE_NAME)));
+ }
+ }
+ }.start();
+ }
+
+ List<ConnectivityMetricsEvent> got = verifyEvents(nCallers * nEvents, 200);
+ Collections.sort(got, EVENT_COMPARATOR);
+ Iterator<ConnectivityMetricsEvent> iter = got.iterator();
+ for (int i = 0; i < nCallers; i++) {
+ for (int j = 0; j < nEvents; j++) {
+ final long expectedTimestamp = FAKE_TIME_STAMP + i * 100 + j;
+ final int expectedNetId = FAKE_NET_ID + i * 100 + j;
+ final long expectedTransports =
+ ((i + j) % 2 == 0) ? TRANSPORT_WIFI : TRANSPORT_CELLULAR;
+ assertEventsEqual(makeExpectedEvent(expectedTimestamp, expectedNetId,
+ expectedTransports, FAKE_INTERFACE_NAME), iter.next());
+ }
+ }
+ }
+
+ private List<ConnectivityMetricsEvent> verifyEvents(int n, int timeoutMs) throws Exception {
+ ArgumentCaptor<ConnectivityMetricsEvent> captor =
+ ArgumentCaptor.forClass(ConnectivityMetricsEvent.class);
+ verify(mMockService, timeout(timeoutMs).times(n)).logEvent(captor.capture());
+ return captor.getAllValues();
+ }
+
+ private List<ConnectivityMetricsEvent> verifyEvents(int n) throws Exception {
+ return verifyEvents(n, 10);
+ }
+
+
+ private ConnectivityMetricsEvent makeExpectedEvent(long timestamp, int netId, long transports,
+ String ifname) {
+ ConnectivityMetricsEvent ev = new ConnectivityMetricsEvent();
+ ev.timestamp = timestamp;
+ ev.data = FAKE_EV;
+ ev.netId = netId;
+ ev.transports = transports;
+ ev.ifname = ifname;
+ return ev;
+ }
+
+ /** Outer equality for ConnectivityMetricsEvent to avoid overriding equals() and hashCode(). */
+ private void assertEventsEqual(ConnectivityMetricsEvent expected,
+ ConnectivityMetricsEvent got) {
+ assertEquals(expected.data, got.data);
+ assertEquals(expected.timestamp, got.timestamp);
+ assertEquals(expected.netId, got.netId);
+ assertEquals(expected.transports, got.transports);
+ assertEquals(expected.ifname, got.ifname);
+ }
+
+ static final Comparator<ConnectivityMetricsEvent> EVENT_COMPARATOR =
+ Comparator.comparingLong((ev) -> ev.timestamp);
+}
diff --git a/tests/net/common/java/android/net/metrics/IpReachabilityEventTest.kt b/tests/net/common/java/android/net/metrics/IpReachabilityEventTest.kt
new file mode 100644
index 0000000..55b5e49
--- /dev/null
+++ b/tests/net/common/java/android/net/metrics/IpReachabilityEventTest.kt
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+package android.net.metrics
+
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.testutils.assertParcelSane
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class IpReachabilityEventTest {
+ @Test
+ fun testConstructorAndParcel() {
+ (IpReachabilityEvent.PROBE..IpReachabilityEvent.PROVISIONING_LOST_ORGANIC).forEach {
+ val ipReachabilityEvent = IpReachabilityEvent(it)
+ assertEquals(it, ipReachabilityEvent.eventType)
+
+ assertParcelSane(ipReachabilityEvent, 1)
+ }
+ }
+}
diff --git a/tests/net/common/java/android/net/metrics/RaEventTest.kt b/tests/net/common/java/android/net/metrics/RaEventTest.kt
new file mode 100644
index 0000000..d9b7203
--- /dev/null
+++ b/tests/net/common/java/android/net/metrics/RaEventTest.kt
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+package android.net.metrics
+
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.testutils.assertParcelSane
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private const val NO_LIFETIME: Long = -1L
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class RaEventTest {
+ @Test
+ fun testConstructorAndParcel() {
+ var raEvent = RaEvent.Builder().build()
+ assertEquals(NO_LIFETIME, raEvent.routerLifetime)
+ assertEquals(NO_LIFETIME, raEvent.prefixValidLifetime)
+ assertEquals(NO_LIFETIME, raEvent.prefixPreferredLifetime)
+ assertEquals(NO_LIFETIME, raEvent.routeInfoLifetime)
+ assertEquals(NO_LIFETIME, raEvent.rdnssLifetime)
+ assertEquals(NO_LIFETIME, raEvent.dnsslLifetime)
+
+ raEvent = RaEvent.Builder()
+ .updateRouterLifetime(1)
+ .updatePrefixValidLifetime(2)
+ .updatePrefixPreferredLifetime(3)
+ .updateRouteInfoLifetime(4)
+ .updateRdnssLifetime(5)
+ .updateDnsslLifetime(6)
+ .build()
+ assertEquals(1, raEvent.routerLifetime)
+ assertEquals(2, raEvent.prefixValidLifetime)
+ assertEquals(3, raEvent.prefixPreferredLifetime)
+ assertEquals(4, raEvent.routeInfoLifetime)
+ assertEquals(5, raEvent.rdnssLifetime)
+ assertEquals(6, raEvent.dnsslLifetime)
+
+ raEvent = RaEvent.Builder()
+ .updateRouterLifetime(Long.MIN_VALUE)
+ .updateRouterLifetime(Long.MAX_VALUE)
+ .build()
+ assertEquals(Long.MIN_VALUE, raEvent.routerLifetime)
+
+ raEvent = RaEvent(1, 2, 3, 4, 5, 6)
+ assertEquals(1, raEvent.routerLifetime)
+ assertEquals(2, raEvent.prefixValidLifetime)
+ assertEquals(3, raEvent.prefixPreferredLifetime)
+ assertEquals(4, raEvent.routeInfoLifetime)
+ assertEquals(5, raEvent.rdnssLifetime)
+ assertEquals(6, raEvent.dnsslLifetime)
+
+ assertParcelSane(raEvent, 6)
+ }
+}
diff --git a/tests/net/common/java/android/net/metrics/ValidationProbeEventTest.kt b/tests/net/common/java/android/net/metrics/ValidationProbeEventTest.kt
new file mode 100644
index 0000000..51c0d41
--- /dev/null
+++ b/tests/net/common/java/android/net/metrics/ValidationProbeEventTest.kt
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+package android.net.metrics
+
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.testutils.assertParcelSane
+import java.lang.reflect.Modifier
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private const val FIRST_VALIDATION: Int = 1 shl 8
+private const val REVALIDATION: Int = 2 shl 8
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class ValidationProbeEventTest {
+ private infix fun Int.hasType(type: Int) = (type and this) == type
+
+ @Test
+ fun testBuilderAndParcel() {
+ var validationProbeEvent = ValidationProbeEvent.Builder()
+ .setProbeType(ValidationProbeEvent.PROBE_DNS, false).build()
+
+ assertTrue(validationProbeEvent.probeType hasType REVALIDATION)
+
+ validationProbeEvent = ValidationProbeEvent.Builder()
+ .setDurationMs(Long.MAX_VALUE)
+ .setProbeType(ValidationProbeEvent.PROBE_DNS, true)
+ .setReturnCode(ValidationProbeEvent.DNS_SUCCESS)
+ .build()
+
+ assertEquals(Long.MAX_VALUE, validationProbeEvent.durationMs)
+ assertTrue(validationProbeEvent.probeType hasType ValidationProbeEvent.PROBE_DNS)
+ assertTrue(validationProbeEvent.probeType hasType FIRST_VALIDATION)
+ assertEquals(ValidationProbeEvent.DNS_SUCCESS, validationProbeEvent.returnCode)
+
+ assertParcelSane(validationProbeEvent, 3)
+ }
+
+ @Test
+ fun testGetProbeName() {
+ val probeFields = ValidationProbeEvent::class.java.declaredFields.filter {
+ it.type == Int::class.javaPrimitiveType
+ && Modifier.isPublic(it.modifiers) && Modifier.isStatic(it.modifiers)
+ && it.name.contains("PROBE")
+ }
+
+ probeFields.forEach {
+ val intValue = it.getInt(null)
+ val stringValue = ValidationProbeEvent.getProbeName(intValue)
+ assertEquals(it.name, stringValue)
+ }
+
+ }
+}
diff --git a/tests/net/common/java/android/net/util/SocketUtilsTest.kt b/tests/net/common/java/android/net/util/SocketUtilsTest.kt
new file mode 100644
index 0000000..9c7cfb0
--- /dev/null
+++ b/tests/net/common/java/android/net/util/SocketUtilsTest.kt
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+package android.net.util;
+
+import android.system.NetlinkSocketAddress
+import android.system.Os
+import android.system.OsConstants.AF_INET
+import android.system.OsConstants.ETH_P_ALL
+import android.system.OsConstants.IPPROTO_UDP
+import android.system.OsConstants.RTMGRP_NEIGH
+import android.system.OsConstants.SOCK_DGRAM
+import android.system.PacketSocketAddress
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Assert.fail
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private const val TEST_INDEX = 123
+private const val TEST_PORT = 555
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class SocketUtilsTest {
+ @Test
+ fun testMakeNetlinkSocketAddress() {
+ val nlAddress = SocketUtils.makeNetlinkSocketAddress(TEST_PORT, RTMGRP_NEIGH)
+ if (nlAddress is NetlinkSocketAddress) {
+ assertEquals(TEST_PORT, nlAddress.getPortId())
+ assertEquals(RTMGRP_NEIGH, nlAddress.getGroupsMask())
+ } else {
+ fail("Not NetlinkSocketAddress object")
+ }
+ }
+
+ @Test
+ fun testMakePacketSocketAddress() {
+ val pkAddress = SocketUtils.makePacketSocketAddress(ETH_P_ALL, TEST_INDEX)
+ assertTrue("Not PacketSocketAddress object", pkAddress is PacketSocketAddress)
+
+ val ff = 0xff.toByte()
+ val pkAddress2 = SocketUtils.makePacketSocketAddress(TEST_INDEX,
+ byteArrayOf(ff, ff, ff, ff, ff, ff))
+ assertTrue("Not PacketSocketAddress object", pkAddress2 is PacketSocketAddress)
+ }
+
+ @Test
+ fun testCloseSocket() {
+ // Expect no exception happening with null object.
+ SocketUtils.closeSocket(null)
+
+ val fd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
+ assertTrue(fd.valid())
+ SocketUtils.closeSocket(fd)
+ assertFalse(fd.valid())
+ // Expecting socket should be still invalid even closed socket again.
+ SocketUtils.closeSocket(fd)
+ assertFalse(fd.valid())
+ }
+}
diff --git a/tests/net/integration/util/com/android/server/ConnectivityServiceTestUtils.kt b/tests/net/integration/util/com/android/server/ConnectivityServiceTestUtils.kt
new file mode 100644
index 0000000..fa2b99c
--- /dev/null
+++ b/tests/net/integration/util/com/android/server/ConnectivityServiceTestUtils.kt
@@ -0,0 +1,41 @@
+/*
+ * 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
+ */
+
+package com.android.server
+
+import android.net.ConnectivityManager.TYPE_BLUETOOTH
+import android.net.ConnectivityManager.TYPE_ETHERNET
+import android.net.ConnectivityManager.TYPE_MOBILE
+import android.net.ConnectivityManager.TYPE_NONE
+import android.net.ConnectivityManager.TYPE_TEST
+import android.net.ConnectivityManager.TYPE_VPN
+import android.net.ConnectivityManager.TYPE_WIFI
+import android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH
+import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
+import android.net.NetworkCapabilities.TRANSPORT_ETHERNET
+import android.net.NetworkCapabilities.TRANSPORT_TEST
+import android.net.NetworkCapabilities.TRANSPORT_VPN
+import android.net.NetworkCapabilities.TRANSPORT_WIFI
+
+fun transportToLegacyType(transport: Int) = when (transport) {
+ TRANSPORT_BLUETOOTH -> TYPE_BLUETOOTH
+ TRANSPORT_CELLULAR -> TYPE_MOBILE
+ TRANSPORT_ETHERNET -> TYPE_ETHERNET
+ TRANSPORT_TEST -> TYPE_TEST
+ TRANSPORT_VPN -> TYPE_VPN
+ TRANSPORT_WIFI -> TYPE_WIFI
+ else -> TYPE_NONE
+}
\ No newline at end of file
diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
new file mode 100644
index 0000000..1e8d83c
--- /dev/null
+++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
@@ -0,0 +1,267 @@
+/*
+ * 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.
+ */
+
+package com.android.server;
+
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
+
+import static com.android.server.ConnectivityServiceTestUtilsKt.transportToLegacyType;
+
+import static junit.framework.Assert.assertTrue;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkAgent;
+import android.net.NetworkCapabilities;
+import android.net.NetworkFactory;
+import android.net.NetworkInfo;
+import android.net.NetworkMisc;
+import android.net.NetworkSpecifier;
+import android.net.SocketKeepalive;
+import android.net.UidRange;
+import android.os.ConditionVariable;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.util.Log;
+
+import com.android.server.connectivity.ConnectivityConstants;
+import com.android.testutils.HandlerUtilsKt;
+import com.android.testutils.TestableNetworkCallback;
+
+import java.util.Set;
+
+public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork {
+ private final NetworkInfo mNetworkInfo;
+ private final NetworkCapabilities mNetworkCapabilities;
+ private final HandlerThread mHandlerThread;
+ private final Context mContext;
+ private final String mLogTag;
+
+ private final ConditionVariable mDisconnected = new ConditionVariable();
+ private final ConditionVariable mPreventReconnectReceived = new ConditionVariable();
+ private int mScore;
+ private NetworkAgent mNetworkAgent;
+ private int mStartKeepaliveError = SocketKeepalive.ERROR_UNSUPPORTED;
+ private int mStopKeepaliveError = SocketKeepalive.NO_KEEPALIVE;
+ private Integer mExpectedKeepaliveSlot = null;
+
+ public NetworkAgentWrapper(int transport, LinkProperties linkProperties, Context context)
+ throws Exception {
+ final int type = transportToLegacyType(transport);
+ final String typeName = ConnectivityManager.getNetworkTypeName(type);
+ mNetworkInfo = new NetworkInfo(type, 0, typeName, "Mock");
+ mNetworkCapabilities = new NetworkCapabilities();
+ mNetworkCapabilities.addTransportType(transport);
+ switch (transport) {
+ case TRANSPORT_ETHERNET:
+ mScore = 70;
+ break;
+ case TRANSPORT_WIFI:
+ mScore = 60;
+ break;
+ case TRANSPORT_CELLULAR:
+ mScore = 50;
+ break;
+ case TRANSPORT_WIFI_AWARE:
+ mScore = 20;
+ break;
+ case TRANSPORT_VPN:
+ mNetworkCapabilities.removeCapability(NET_CAPABILITY_NOT_VPN);
+ mScore = ConnectivityConstants.VPN_DEFAULT_SCORE;
+ break;
+ default:
+ throw new UnsupportedOperationException("unimplemented network type");
+ }
+ mContext = context;
+ mLogTag = "Mock-" + typeName;
+ mHandlerThread = new HandlerThread(mLogTag);
+ mHandlerThread.start();
+
+ mNetworkAgent = makeNetworkAgent(linkProperties);
+ }
+
+ protected InstrumentedNetworkAgent makeNetworkAgent(LinkProperties linkProperties)
+ throws Exception {
+ return new InstrumentedNetworkAgent(this, linkProperties);
+ }
+
+ public static class InstrumentedNetworkAgent extends NetworkAgent {
+ private final NetworkAgentWrapper mWrapper;
+
+ public InstrumentedNetworkAgent(NetworkAgentWrapper wrapper, LinkProperties lp) {
+ super(wrapper.mHandlerThread.getLooper(), wrapper.mContext, wrapper.mLogTag,
+ wrapper.mNetworkInfo, wrapper.mNetworkCapabilities, lp, wrapper.mScore,
+ new NetworkMisc(), NetworkFactory.SerialNumber.NONE);
+ mWrapper = wrapper;
+ }
+
+ @Override
+ public void unwanted() {
+ mWrapper.mDisconnected.open();
+ }
+
+ @Override
+ public void startSocketKeepalive(Message msg) {
+ int slot = msg.arg1;
+ if (mWrapper.mExpectedKeepaliveSlot != null) {
+ assertEquals((int) mWrapper.mExpectedKeepaliveSlot, slot);
+ }
+ onSocketKeepaliveEvent(slot, mWrapper.mStartKeepaliveError);
+ }
+
+ @Override
+ public void stopSocketKeepalive(Message msg) {
+ onSocketKeepaliveEvent(msg.arg1, mWrapper.mStopKeepaliveError);
+ }
+
+ @Override
+ protected void preventAutomaticReconnect() {
+ mWrapper.mPreventReconnectReceived.open();
+ }
+
+ @Override
+ protected void addKeepalivePacketFilter(Message msg) {
+ Log.i(mWrapper.mLogTag, "Add keepalive packet filter.");
+ }
+
+ @Override
+ protected void removeKeepalivePacketFilter(Message msg) {
+ Log.i(mWrapper.mLogTag, "Remove keepalive packet filter.");
+ }
+ }
+
+ public void adjustScore(int change) {
+ mScore += change;
+ mNetworkAgent.sendNetworkScore(mScore);
+ }
+
+ public int getScore() {
+ return mScore;
+ }
+
+ public void explicitlySelected(boolean explicitlySelected, boolean acceptUnvalidated) {
+ mNetworkAgent.explicitlySelected(explicitlySelected, acceptUnvalidated);
+ }
+
+ public void addCapability(int capability) {
+ mNetworkCapabilities.addCapability(capability);
+ mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+ }
+
+ public void removeCapability(int capability) {
+ mNetworkCapabilities.removeCapability(capability);
+ mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+ }
+
+ public void setUids(Set<UidRange> uids) {
+ mNetworkCapabilities.setUids(uids);
+ mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+ }
+
+ public void setSignalStrength(int signalStrength) {
+ mNetworkCapabilities.setSignalStrength(signalStrength);
+ mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+ }
+
+ public void setNetworkSpecifier(NetworkSpecifier networkSpecifier) {
+ mNetworkCapabilities.setNetworkSpecifier(networkSpecifier);
+ mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+ }
+
+ public void setNetworkCapabilities(NetworkCapabilities nc, boolean sendToConnectivityService) {
+ mNetworkCapabilities.set(nc);
+ if (sendToConnectivityService) {
+ mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+ }
+ }
+
+ public void connect() {
+ assertNotEquals("MockNetworkAgents can only be connected once",
+ getNetworkInfo().getDetailedState(), NetworkInfo.DetailedState.CONNECTED);
+ mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
+ mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+ }
+
+ public void suspend() {
+ mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.SUSPENDED, null, null);
+ mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+ }
+
+ public void resume() {
+ mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
+ mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+ }
+
+ public void disconnect() {
+ mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
+ mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+ }
+
+ @Override
+ public Network getNetwork() {
+ return new Network(mNetworkAgent.netId);
+ }
+
+ public void expectPreventReconnectReceived(long timeoutMs) {
+ assertTrue(mPreventReconnectReceived.block(timeoutMs));
+ }
+
+ public void expectDisconnected(long timeoutMs) {
+ assertTrue(mDisconnected.block(timeoutMs));
+ }
+
+ public void sendLinkProperties(LinkProperties lp) {
+ mNetworkAgent.sendLinkProperties(lp);
+ }
+
+ public void setStartKeepaliveEvent(int reason) {
+ mStartKeepaliveError = reason;
+ }
+
+ public void setStopKeepaliveEvent(int reason) {
+ mStopKeepaliveError = reason;
+ }
+
+ public void setExpectedKeepaliveSlot(Integer slot) {
+ mExpectedKeepaliveSlot = slot;
+ }
+
+ public NetworkAgent getNetworkAgent() {
+ return mNetworkAgent;
+ }
+
+ public NetworkInfo getNetworkInfo() {
+ return mNetworkInfo;
+ }
+
+ public NetworkCapabilities getNetworkCapabilities() {
+ return mNetworkCapabilities;
+ }
+
+ public void waitForIdle(long timeoutMs) {
+ HandlerUtilsKt.waitForIdle(mHandlerThread, timeoutMs);
+ }
+}
diff --git a/tests/net/integration/util/com/android/server/TestNetIdManager.kt b/tests/net/integration/util/com/android/server/TestNetIdManager.kt
new file mode 100644
index 0000000..eb290dc
--- /dev/null
+++ b/tests/net/integration/util/com/android/server/TestNetIdManager.kt
@@ -0,0 +1,38 @@
+/*
+ * 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
+ */
+
+package com.android.server
+
+import java.util.concurrent.atomic.AtomicInteger
+
+/**
+ * A [NetIdManager] that generates ID starting from [NetIdManager.MAX_NET_ID] and decreasing, rather
+ * than starting from [NetIdManager.MIN_NET_ID] and increasing.
+ *
+ * Useful for testing ConnectivityService, to minimize the risk of test ConnectivityService netIDs
+ * overlapping with netIDs used by the real ConnectivityService on the device.
+ *
+ * IDs may still overlap if many networks have been used on the device (so the "real" netIDs
+ * are close to MAX_NET_ID), but this is typically not the case when running unit tests. Also, there
+ * is no way to fully solve the overlap issue without altering ID allocation in non-test code, as
+ * the real ConnectivityService could start using netIds that have been used by the test in the
+ * past.
+ */
+class TestNetIdManager : NetIdManager() {
+ private val nextId = AtomicInteger(MAX_NET_ID)
+ override fun reserveNetId() = nextId.decrementAndGet()
+ override fun releaseNetId(id: Int) = Unit
+}
diff --git a/tests/net/java/android/app/usage/NetworkStatsManagerTest.java b/tests/net/java/android/app/usage/NetworkStatsManagerTest.java
index fd555c1..899295a 100644
--- a/tests/net/java/android/app/usage/NetworkStatsManagerTest.java
+++ b/tests/net/java/android/app/usage/NetworkStatsManagerTest.java
@@ -202,8 +202,7 @@
assertFalse(stats.hasNextBucket());
}
- private void assertBucketMatches(Entry expected,
- NetworkStats.Bucket actual) {
+ private void assertBucketMatches(Entry expected, NetworkStats.Bucket actual) {
assertEquals(expected.uid, actual.getUid());
assertEquals(expected.rxBytes, actual.getRxBytes());
assertEquals(expected.rxPackets, actual.getRxPackets());
diff --git a/tests/net/java/android/net/IpMemoryStoreTest.java b/tests/net/java/android/net/IpMemoryStoreTest.java
index 18c6768..b81ca36 100644
--- a/tests/net/java/android/net/IpMemoryStoreTest.java
+++ b/tests/net/java/android/net/IpMemoryStoreTest.java
@@ -16,10 +16,26 @@
package android.net;
-import static org.mockito.ArgumentMatchers.any;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import android.content.Context;
+import android.net.ipmemorystore.Blob;
+import android.net.ipmemorystore.IOnStatusListener;
+import android.net.ipmemorystore.NetworkAttributes;
+import android.net.ipmemorystore.NetworkAttributesParcelable;
+import android.net.ipmemorystore.Status;
+import android.os.RemoteException;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -27,28 +43,57 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+
@RunWith(AndroidJUnit4.class)
@SmallTest
public class IpMemoryStoreTest {
+ private static final String TAG = IpMemoryStoreTest.class.getSimpleName();
+ private static final String TEST_CLIENT_ID = "testClientId";
+ private static final String TEST_DATA_NAME = "testData";
+ private static final String TEST_OTHER_DATA_NAME = TEST_DATA_NAME + "Other";
+ private static final byte[] TEST_BLOB_DATA = new byte[] { -3, 6, 8, -9, 12,
+ -128, 0, 89, 112, 91, -34 };
+ private static final NetworkAttributes TEST_NETWORK_ATTRIBUTES = buildTestNetworkAttributes(
+ "hint", 219);
+
@Mock
Context mMockContext;
@Mock
NetworkStackClient mNetworkStackClient;
@Mock
IIpMemoryStore mMockService;
+ @Mock
+ IOnStatusListener mIOnStatusListener;
IpMemoryStore mStore;
+ @Captor
+ ArgumentCaptor<IIpMemoryStoreCallbacks> mCbCaptor;
+ @Captor
+ ArgumentCaptor<NetworkAttributesParcelable> mNapCaptor;
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- doAnswer(invocation -> {
- ((IIpMemoryStoreCallbacks) invocation.getArgument(0))
- .onIpMemoryStoreFetched(mMockService);
- return null;
- }).when(mNetworkStackClient).fetchIpMemoryStore(any());
+ }
+
+ private void startIpMemoryStore(boolean supplyService) {
+ if (supplyService) {
+ doAnswer(invocation -> {
+ ((IIpMemoryStoreCallbacks) invocation.getArgument(0))
+ .onIpMemoryStoreFetched(mMockService);
+ return null;
+ }).when(mNetworkStackClient).fetchIpMemoryStore(any());
+ } else {
+ doNothing().when(mNetworkStackClient).fetchIpMemoryStore(mCbCaptor.capture());
+ }
mStore = new IpMemoryStore(mMockContext) {
@Override
protected NetworkStackClient getNetworkStackClient() {
@@ -57,24 +102,230 @@
};
}
- @Test
- public void testNetworkAttributes() {
- // TODO : implement this
+ private static NetworkAttributes buildTestNetworkAttributes(String hint, int mtu) {
+ return new NetworkAttributes.Builder()
+ .setGroupHint(hint)
+ .setMtu(mtu)
+ .build();
}
@Test
- public void testPrivateData() {
- // TODO : implement this
+ public void testNetworkAttributes() throws Exception {
+ startIpMemoryStore(true /* supplyService */);
+ final String l2Key = "fakeKey";
+
+ mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES,
+ status -> assertTrue("Store not successful : " + status.resultCode,
+ status.isSuccess()));
+ verify(mMockService, times(1)).storeNetworkAttributes(eq(l2Key),
+ mNapCaptor.capture(), any());
+ assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
+
+ mStore.retrieveNetworkAttributes(l2Key,
+ (status, key, attr) -> {
+ assertTrue("Retrieve network attributes not successful : "
+ + status.resultCode, status.isSuccess());
+ assertEquals(l2Key, key);
+ assertEquals(TEST_NETWORK_ATTRIBUTES, attr);
+ });
+
+ verify(mMockService, times(1)).retrieveNetworkAttributes(eq(l2Key), any());
}
@Test
- public void testFindL2Key() {
- // TODO : implement this
+ public void testPrivateData() throws RemoteException {
+ startIpMemoryStore(true /* supplyService */);
+ final Blob b = new Blob();
+ b.data = TEST_BLOB_DATA;
+ final String l2Key = "fakeKey";
+
+ mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b,
+ status -> {
+ assertTrue("Store not successful : " + status.resultCode, status.isSuccess());
+ });
+ verify(mMockService, times(1)).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME),
+ eq(b), any());
+
+ mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME,
+ (status, key, name, data) -> {
+ assertTrue("Retrieve blob status not successful : " + status.resultCode,
+ status.isSuccess());
+ assertEquals(l2Key, key);
+ assertEquals(name, TEST_DATA_NAME);
+ assertTrue(Arrays.equals(b.data, data.data));
+ });
+ verify(mMockService, times(1)).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID),
+ eq(TEST_OTHER_DATA_NAME), any());
}
@Test
- public void testIsSameNetwork() {
- // TODO : implement this
+ public void testFindL2Key()
+ throws UnknownHostException, RemoteException, Exception {
+ startIpMemoryStore(true /* supplyService */);
+ final String l2Key = "fakeKey";
+
+ mStore.findL2Key(TEST_NETWORK_ATTRIBUTES,
+ (status, key) -> {
+ assertTrue("Retrieve network sameness not successful : " + status.resultCode,
+ status.isSuccess());
+ assertEquals(l2Key, key);
+ });
+ verify(mMockService, times(1)).findL2Key(mNapCaptor.capture(), any());
+ assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
}
+ @Test
+ public void testIsSameNetwork() throws UnknownHostException, RemoteException {
+ startIpMemoryStore(true /* supplyService */);
+ final String l2Key1 = "fakeKey1";
+ final String l2Key2 = "fakeKey2";
+
+ mStore.isSameNetwork(l2Key1, l2Key2,
+ (status, answer) -> {
+ assertFalse("Retrieve network sameness suspiciously successful : "
+ + status.resultCode, status.isSuccess());
+ assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode);
+ assertNull(answer);
+ });
+ verify(mMockService, times(1)).isSameNetwork(eq(l2Key1), eq(l2Key2), any());
+ }
+
+ @Test
+ public void testEnqueuedIpMsRequests() throws Exception {
+ startIpMemoryStore(false /* supplyService */);
+
+ final Blob b = new Blob();
+ b.data = TEST_BLOB_DATA;
+ final String l2Key = "fakeKey";
+
+ // enqueue multiple ipms requests
+ mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES,
+ status -> assertTrue("Store not successful : " + status.resultCode,
+ status.isSuccess()));
+ mStore.retrieveNetworkAttributes(l2Key,
+ (status, key, attr) -> {
+ assertTrue("Retrieve network attributes not successful : "
+ + status.resultCode, status.isSuccess());
+ assertEquals(l2Key, key);
+ assertEquals(TEST_NETWORK_ATTRIBUTES, attr);
+ });
+ mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b,
+ status -> assertTrue("Store not successful : " + status.resultCode,
+ status.isSuccess()));
+ mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME,
+ (status, key, name, data) -> {
+ assertTrue("Retrieve blob status not successful : " + status.resultCode,
+ status.isSuccess());
+ assertEquals(l2Key, key);
+ assertEquals(name, TEST_DATA_NAME);
+ assertTrue(Arrays.equals(b.data, data.data));
+ });
+
+ // get ipms service ready
+ mCbCaptor.getValue().onIpMemoryStoreFetched(mMockService);
+
+ InOrder inOrder = inOrder(mMockService);
+
+ inOrder.verify(mMockService).storeNetworkAttributes(eq(l2Key), mNapCaptor.capture(), any());
+ inOrder.verify(mMockService).retrieveNetworkAttributes(eq(l2Key), any());
+ inOrder.verify(mMockService).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME),
+ eq(b), any());
+ inOrder.verify(mMockService).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID),
+ eq(TEST_OTHER_DATA_NAME), any());
+ assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
+ }
+
+ @Test
+ public void testEnqueuedIpMsRequestsWithException() throws Exception {
+ startIpMemoryStore(true /* supplyService */);
+ doThrow(RemoteException.class).when(mMockService).retrieveNetworkAttributes(any(), any());
+
+ final Blob b = new Blob();
+ b.data = TEST_BLOB_DATA;
+ final String l2Key = "fakeKey";
+
+ // enqueue multiple ipms requests
+ mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES,
+ status -> assertTrue("Store not successful : " + status.resultCode,
+ status.isSuccess()));
+ mStore.retrieveNetworkAttributes(l2Key,
+ (status, key, attr) -> {
+ assertTrue("Retrieve network attributes not successful : "
+ + status.resultCode, status.isSuccess());
+ assertEquals(l2Key, key);
+ assertEquals(TEST_NETWORK_ATTRIBUTES, attr);
+ });
+ mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b,
+ status -> assertTrue("Store not successful : " + status.resultCode,
+ status.isSuccess()));
+ mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME,
+ (status, key, name, data) -> {
+ assertTrue("Retrieve blob status not successful : " + status.resultCode,
+ status.isSuccess());
+ assertEquals(l2Key, key);
+ assertEquals(name, TEST_DATA_NAME);
+ assertTrue(Arrays.equals(b.data, data.data));
+ });
+
+ // verify the rest of the queue is still processed in order even if the remote exception
+ // occurs when calling one or more requests
+ InOrder inOrder = inOrder(mMockService);
+
+ inOrder.verify(mMockService).storeNetworkAttributes(eq(l2Key), mNapCaptor.capture(), any());
+ inOrder.verify(mMockService).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME),
+ eq(b), any());
+ inOrder.verify(mMockService).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID),
+ eq(TEST_OTHER_DATA_NAME), any());
+ assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
+ }
+
+ @Test
+ public void testEnqueuedIpMsRequestsCallbackFunctionWithException() throws Exception {
+ startIpMemoryStore(true /* supplyService */);
+
+ final Blob b = new Blob();
+ b.data = TEST_BLOB_DATA;
+ final String l2Key = "fakeKey";
+
+ // enqueue multiple ipms requests
+ mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES,
+ status -> assertTrue("Store not successful : " + status.resultCode,
+ status.isSuccess()));
+ mStore.retrieveNetworkAttributes(l2Key,
+ (status, key, attr) -> {
+ throw new RuntimeException("retrieveNetworkAttributes test");
+ });
+ mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b,
+ status -> {
+ throw new RuntimeException("storeBlob test");
+ });
+ mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME,
+ (status, key, name, data) -> {
+ assertTrue("Retrieve blob status not successful : " + status.resultCode,
+ status.isSuccess());
+ assertEquals(l2Key, key);
+ assertEquals(name, TEST_DATA_NAME);
+ assertTrue(Arrays.equals(b.data, data.data));
+ });
+
+ // verify the rest of the queue is still processed in order even if when one or more
+ // callback throw the remote exception
+ InOrder inOrder = inOrder(mMockService);
+
+ inOrder.verify(mMockService).storeNetworkAttributes(eq(l2Key), mNapCaptor.capture(),
+ any());
+ inOrder.verify(mMockService).retrieveNetworkAttributes(eq(l2Key), any());
+ inOrder.verify(mMockService).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME),
+ eq(b), any());
+ inOrder.verify(mMockService).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID),
+ eq(TEST_OTHER_DATA_NAME), any());
+ assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
+ }
+
+ @Test
+ public void testFactoryReset() throws RemoteException {
+ startIpMemoryStore(true /* supplyService */);
+ mStore.factoryReset();
+ verify(mMockService, times(1)).factoryReset();
+ }
}
diff --git a/tests/net/java/android/net/IpSecConfigTest.java b/tests/net/java/android/net/IpSecConfigTest.java
index 215506c..c9888b2 100644
--- a/tests/net/java/android/net/IpSecConfigTest.java
+++ b/tests/net/java/android/net/IpSecConfigTest.java
@@ -16,12 +16,12 @@
package android.net;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
+import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
+import static com.android.testutils.ParcelUtilsKt.assertParcelingIsLossless;
-import android.os.Parcel;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
import androidx.test.filters.SmallTest;
@@ -89,23 +89,15 @@
IpSecConfig original = getSampleConfig();
IpSecConfig copy = new IpSecConfig(original);
- assertTrue(IpSecConfig.equals(original, copy));
- assertFalse(original == copy);
+ assertEquals(original, copy);
+ assertNotSame(original, copy);
}
@Test
- public void testParcelUnparcel() throws Exception {
+ public void testParcelUnparcel() {
assertParcelingIsLossless(new IpSecConfig());
IpSecConfig c = getSampleConfig();
- assertParcelingIsLossless(c);
- }
-
- private void assertParcelingIsLossless(IpSecConfig ci) throws Exception {
- Parcel p = Parcel.obtain();
- ci.writeToParcel(p, 0);
- p.setDataPosition(0);
- IpSecConfig co = IpSecConfig.CREATOR.createFromParcel(p);
- assertTrue(IpSecConfig.equals(co, ci));
+ assertParcelSane(c, 15);
}
}
diff --git a/tests/net/java/android/net/IpSecTransformTest.java b/tests/net/java/android/net/IpSecTransformTest.java
index 2308a3c..424f23d 100644
--- a/tests/net/java/android/net/IpSecTransformTest.java
+++ b/tests/net/java/android/net/IpSecTransformTest.java
@@ -16,8 +16,8 @@
package android.net;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
import androidx.test.filters.SmallTest;
@@ -43,7 +43,7 @@
config.setSpiResourceId(1985);
IpSecTransform postModification = new IpSecTransform(null, config);
- assertFalse(IpSecTransform.equals(preModification, postModification));
+ assertNotEquals(preModification, postModification);
}
@Test
@@ -57,6 +57,6 @@
IpSecTransform config1 = new IpSecTransform(null, config);
IpSecTransform config2 = new IpSecTransform(null, config);
- assertTrue(IpSecTransform.equals(config1, config2));
+ assertEquals(config1, config2);
}
}
diff --git a/tests/net/java/android/net/TcpKeepalivePacketDataTest.java b/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
index e0b7227..5cb0d7e 100644
--- a/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
+++ b/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
@@ -16,14 +16,14 @@
package android.net;
+import static com.android.testutils.ParcelUtilsKt.assertParcelingIsLossless;
+
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import android.net.SocketKeepalive.InvalidPacketException;
-import com.android.internal.util.TestUtils;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -79,7 +79,7 @@
assertEquals(testInfo.tos, resultData.ipTos);
assertEquals(testInfo.ttl, resultData.ipTtl);
- TestUtils.assertParcelingIsLossless(resultData, TcpKeepalivePacketData.CREATOR);
+ assertParcelingIsLossless(resultData);
final byte[] packet = resultData.getPacket();
// IP version and IHL
diff --git a/tests/net/java/android/net/nsd/NsdManagerTest.java b/tests/net/java/android/net/nsd/NsdManagerTest.java
index 2d2bccb..cf7587a 100644
--- a/tests/net/java/android/net/nsd/NsdManagerTest.java
+++ b/tests/net/java/android/net/nsd/NsdManagerTest.java
@@ -16,8 +16,6 @@
package android.net.nsd;
-import static com.android.internal.util.TestUtils.waitForIdleHandler;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
@@ -40,6 +38,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.AsyncChannel;
+import com.android.testutils.HandlerUtilsKt;
import org.junit.After;
import org.junit.Before;
@@ -74,7 +73,7 @@
@After
public void tearDown() throws Exception {
- mServiceHandler.waitForIdle(mTimeoutMs);
+ HandlerUtilsKt.waitForIdle(mServiceHandler, mTimeoutMs);
mServiceHandler.chan.disconnect();
mServiceHandler.stop();
if (mManager != null) {
@@ -334,7 +333,7 @@
}
int verifyRequest(int expectedMessageType) {
- mServiceHandler.waitForIdle(mTimeoutMs);
+ HandlerUtilsKt.waitForIdle(mServiceHandler, mTimeoutMs);
verify(mServiceHandler, timeout(mTimeoutMs)).handleMessage(any());
reset(mServiceHandler);
Message received = mServiceHandler.getLastMessage();
@@ -366,10 +365,6 @@
lastMessage.copyFrom(msg);
}
- void waitForIdle(long timeoutMs) {
- waitForIdleHandler(this, timeoutMs);
- }
-
@Override
public void handleMessage(Message msg) {
setLastMessage(msg);
diff --git a/tests/net/java/android/net/util/DnsUtilsTest.java b/tests/net/java/android/net/util/DnsUtilsTest.java
new file mode 100644
index 0000000..b626db8
--- /dev/null
+++ b/tests/net/java/android/net/util/DnsUtilsTest.java
@@ -0,0 +1,216 @@
+/*
+ * 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.
+ */
+
+package android.net.util;
+
+import static android.net.util.DnsUtils.IPV6_ADDR_SCOPE_GLOBAL;
+import static android.net.util.DnsUtils.IPV6_ADDR_SCOPE_LINKLOCAL;
+import static android.net.util.DnsUtils.IPV6_ADDR_SCOPE_SITELOCAL;
+
+import static org.junit.Assert.assertEquals;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.InetAddresses;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.InetAddress;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class DnsUtilsTest {
+ private InetAddress stringToAddress(@NonNull String addr) {
+ return InetAddresses.parseNumericAddress(addr);
+ }
+
+ private DnsUtils.SortableAddress makeSortableAddress(@NonNull String addr) {
+ return makeSortableAddress(addr, null);
+ }
+
+ private DnsUtils.SortableAddress makeSortableAddress(@NonNull String addr,
+ @Nullable String srcAddr) {
+ return new DnsUtils.SortableAddress(stringToAddress(addr),
+ srcAddr != null ? stringToAddress(srcAddr) : null);
+ }
+
+ @Test
+ public void testRfc6724Comparator() {
+ final List<DnsUtils.SortableAddress> test = Arrays.asList(
+ // Ipv4
+ makeSortableAddress("216.58.200.36", "192.168.1.1"),
+ // global with different scope src
+ makeSortableAddress("2404:6800:4008:801::2004", "fe80::1111:2222"),
+ // global without src addr
+ makeSortableAddress("2404:6800:cafe:801::1"),
+ // loop back
+ makeSortableAddress("::1", "::1"),
+ // link local
+ makeSortableAddress("fe80::c46f:1cff:fe04:39b4", "fe80::1"),
+ // teredo tunneling
+ makeSortableAddress("2001::47c1", "2001::2"),
+ // 6bone without src addr
+ makeSortableAddress("3ffe::1234:5678"),
+ // IPv4-compatible
+ makeSortableAddress("::216.58.200.36", "::216.58.200.9"),
+ // 6bone
+ makeSortableAddress("3ffe::1234:5678", "3ffe::1234:1"),
+ // IPv4-mapped IPv6
+ makeSortableAddress("::ffff:192.168.95.7", "::ffff:192.168.95.1"));
+
+ final List<InetAddress> expected = Arrays.asList(
+ stringToAddress("::1"), // loop back
+ stringToAddress("fe80::c46f:1cff:fe04:39b4"), // link local
+ stringToAddress("216.58.200.36"), // Ipv4
+ stringToAddress("::ffff:192.168.95.7"), // IPv4-mapped IPv6
+ stringToAddress("2001::47c1"), // teredo tunneling
+ stringToAddress("::216.58.200.36"), // IPv4-compatible
+ stringToAddress("3ffe::1234:5678"), // 6bone
+ stringToAddress("2404:6800:4008:801::2004"), // global with different scope src
+ stringToAddress("2404:6800:cafe:801::1"), // global without src addr
+ stringToAddress("3ffe::1234:5678")); // 6bone without src addr
+
+ Collections.sort(test, new DnsUtils.Rfc6724Comparator());
+
+ for (int i = 0; i < test.size(); ++i) {
+ assertEquals(test.get(i).address, expected.get(i));
+ }
+
+ // TODO: add more combinations
+ }
+
+ @Test
+ public void testV4SortableAddress() {
+ // Test V4 address
+ DnsUtils.SortableAddress test = makeSortableAddress("216.58.200.36");
+ assertEquals(test.hasSrcAddr, 0);
+ assertEquals(test.prefixMatchLen, 0);
+ assertEquals(test.address, stringToAddress("216.58.200.36"));
+ assertEquals(test.labelMatch, 0);
+ assertEquals(test.scopeMatch, 0);
+ assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
+ assertEquals(test.label, 4);
+ assertEquals(test.precedence, 35);
+
+ // Test V4 loopback address with the same source address
+ test = makeSortableAddress("127.1.2.3", "127.1.2.3");
+ assertEquals(test.hasSrcAddr, 1);
+ assertEquals(test.prefixMatchLen, 0);
+ assertEquals(test.address, stringToAddress("127.1.2.3"));
+ assertEquals(test.labelMatch, 1);
+ assertEquals(test.scopeMatch, 1);
+ assertEquals(test.scope, IPV6_ADDR_SCOPE_LINKLOCAL);
+ assertEquals(test.label, 4);
+ assertEquals(test.precedence, 35);
+ }
+
+ @Test
+ public void testV6SortableAddress() {
+ // Test global address
+ DnsUtils.SortableAddress test = makeSortableAddress("2404:6800:4008:801::2004");
+ assertEquals(test.address, stringToAddress("2404:6800:4008:801::2004"));
+ assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
+ assertEquals(test.label, 1);
+ assertEquals(test.precedence, 40);
+
+ // Test global address with global source address
+ test = makeSortableAddress("2404:6800:4008:801::2004",
+ "2401:fa00:fc:fd00:6d6c:7199:b8e7:41d6");
+ assertEquals(test.address, stringToAddress("2404:6800:4008:801::2004"));
+ assertEquals(test.hasSrcAddr, 1);
+ assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
+ assertEquals(test.labelMatch, 1);
+ assertEquals(test.scopeMatch, 1);
+ assertEquals(test.label, 1);
+ assertEquals(test.precedence, 40);
+ assertEquals(test.prefixMatchLen, 13);
+
+ // Test global address with linklocal source address
+ test = makeSortableAddress("2404:6800:4008:801::2004", "fe80::c46f:1cff:fe04:39b4");
+ assertEquals(test.hasSrcAddr, 1);
+ assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
+ assertEquals(test.labelMatch, 1);
+ assertEquals(test.scopeMatch, 0);
+ assertEquals(test.label, 1);
+ assertEquals(test.precedence, 40);
+ assertEquals(test.prefixMatchLen, 0);
+
+ // Test loopback address with the same source address
+ test = makeSortableAddress("::1", "::1");
+ assertEquals(test.hasSrcAddr, 1);
+ assertEquals(test.prefixMatchLen, 16 * 8);
+ assertEquals(test.labelMatch, 1);
+ assertEquals(test.scopeMatch, 1);
+ assertEquals(test.scope, IPV6_ADDR_SCOPE_LINKLOCAL);
+ assertEquals(test.label, 0);
+ assertEquals(test.precedence, 50);
+
+ // Test linklocal address
+ test = makeSortableAddress("fe80::c46f:1cff:fe04:39b4");
+ assertEquals(test.scope, IPV6_ADDR_SCOPE_LINKLOCAL);
+ assertEquals(test.label, 1);
+ assertEquals(test.precedence, 40);
+
+ // Test linklocal address
+ test = makeSortableAddress("fe80::");
+ assertEquals(test.scope, IPV6_ADDR_SCOPE_LINKLOCAL);
+ assertEquals(test.label, 1);
+ assertEquals(test.precedence, 40);
+
+ // Test 6to4 address
+ test = makeSortableAddress("2002:c000:0204::");
+ assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
+ assertEquals(test.label, 2);
+ assertEquals(test.precedence, 30);
+
+ // Test unique local address
+ test = makeSortableAddress("fc00::c000:13ab");
+ assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
+ assertEquals(test.label, 13);
+ assertEquals(test.precedence, 3);
+
+ // Test teredo tunneling address
+ test = makeSortableAddress("2001::47c1");
+ assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
+ assertEquals(test.label, 5);
+ assertEquals(test.precedence, 5);
+
+ // Test IPv4-compatible addresses
+ test = makeSortableAddress("::216.58.200.36");
+ assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
+ assertEquals(test.label, 3);
+ assertEquals(test.precedence, 1);
+
+ // Test site-local address
+ test = makeSortableAddress("fec0::cafe:3ab2");
+ assertEquals(test.scope, IPV6_ADDR_SCOPE_SITELOCAL);
+ assertEquals(test.label, 11);
+ assertEquals(test.precedence, 1);
+
+ // Test 6bone address
+ test = makeSortableAddress("3ffe::1234:5678");
+ assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
+ assertEquals(test.label, 12);
+ assertEquals(test.precedence, 1);
+ }
+}
diff --git a/tests/net/java/android/net/util/KeepaliveUtilsTest.kt b/tests/net/java/android/net/util/KeepaliveUtilsTest.kt
new file mode 100644
index 0000000..8ea226d
--- /dev/null
+++ b/tests/net/java/android/net/util/KeepaliveUtilsTest.kt
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+
+package android.net.util
+
+import android.content.Context
+import android.content.res.Resources
+import android.net.NetworkCapabilities
+import android.net.NetworkCapabilities.MAX_TRANSPORT
+import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
+import android.net.NetworkCapabilities.TRANSPORT_ETHERNET
+import android.net.NetworkCapabilities.TRANSPORT_VPN
+import android.net.NetworkCapabilities.TRANSPORT_WIFI
+import androidx.test.filters.SmallTest
+import com.android.internal.R
+import org.junit.Assert.assertArrayEquals
+import org.junit.Assert.assertEquals
+import org.junit.Assert.fail
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.ArgumentMatchers
+import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.mock
+
+/**
+ * Tests for [KeepaliveUtils].
+ *
+ * Build, install and run with:
+ * atest android.net.util.KeepaliveUtilsTest
+ */
+@RunWith(JUnit4::class)
+@SmallTest
+class KeepaliveUtilsTest {
+
+ // Prepare mocked context with given resource strings.
+ private fun getMockedContextWithStringArrayRes(id: Int, res: Array<out String?>?): Context {
+ val mockRes = mock(Resources::class.java)
+ doReturn(res).`when`(mockRes).getStringArray(ArgumentMatchers.eq(id))
+
+ return mock(Context::class.java).apply {
+ doReturn(mockRes).`when`(this).getResources()
+ }
+ }
+
+ @Test
+ fun testGetSupportedKeepalives() {
+ fun assertRunWithException(res: Array<out String?>?) {
+ try {
+ val mockContext = getMockedContextWithStringArrayRes(
+ R.array.config_networkSupportedKeepaliveCount, res)
+ KeepaliveUtils.getSupportedKeepalives(mockContext)
+ fail("Expected KeepaliveDeviceConfigurationException")
+ } catch (expected: KeepaliveUtils.KeepaliveDeviceConfigurationException) {
+ }
+ }
+
+ // Check resource with various invalid format.
+ assertRunWithException(null)
+ assertRunWithException(arrayOf<String?>(null))
+ assertRunWithException(arrayOfNulls<String?>(10))
+ assertRunWithException(arrayOf(""))
+ assertRunWithException(arrayOf("3,ABC"))
+ assertRunWithException(arrayOf("6,3,3"))
+ assertRunWithException(arrayOf("5"))
+
+ // Check resource with invalid slots value.
+ assertRunWithException(arrayOf("3,-1"))
+
+ // Check resource with invalid transport type.
+ assertRunWithException(arrayOf("-1,3"))
+ assertRunWithException(arrayOf("10,3"))
+
+ // Check valid customization generates expected array.
+ val validRes = arrayOf("0,3", "1,0", "4,4")
+ val expectedValidRes = intArrayOf(3, 0, 0, 0, 4, 0, 0, 0)
+
+ val mockContext = getMockedContextWithStringArrayRes(
+ R.array.config_networkSupportedKeepaliveCount, validRes)
+ val actual = KeepaliveUtils.getSupportedKeepalives(mockContext)
+ assertArrayEquals(expectedValidRes, actual)
+ }
+
+ @Test
+ fun testGetSupportedKeepalivesForNetworkCapabilities() {
+ // Mock customized supported keepalives for each transport type, and assuming:
+ // 3 for cellular,
+ // 6 for wifi,
+ // 0 for others.
+ val cust = IntArray(MAX_TRANSPORT + 1).apply {
+ this[TRANSPORT_CELLULAR] = 3
+ this[TRANSPORT_WIFI] = 6
+ }
+
+ val nc = NetworkCapabilities()
+ // Check supported keepalives with single transport type.
+ nc.transportTypes = intArrayOf(TRANSPORT_CELLULAR)
+ assertEquals(3, KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(cust, nc))
+
+ // Check supported keepalives with multiple transport types.
+ nc.transportTypes = intArrayOf(TRANSPORT_WIFI, TRANSPORT_VPN)
+ assertEquals(0, KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(cust, nc))
+
+ // Check supported keepalives with non-customized transport type.
+ nc.transportTypes = intArrayOf(TRANSPORT_ETHERNET)
+ assertEquals(0, KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(cust, nc))
+
+ // Check supported keepalives with undefined transport type.
+ nc.transportTypes = intArrayOf(MAX_TRANSPORT + 1)
+ try {
+ KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(cust, nc)
+ fail("Expected ArrayIndexOutOfBoundsException")
+ } catch (expected: ArrayIndexOutOfBoundsException) {
+ }
+ }
+}
diff --git a/tests/net/java/com/android/internal/util/RingBufferTest.java b/tests/net/java/com/android/internal/util/RingBufferTest.java
index eff334f..d06095a 100644
--- a/tests/net/java/com/android/internal/util/RingBufferTest.java
+++ b/tests/net/java/com/android/internal/util/RingBufferTest.java
@@ -16,6 +16,7 @@
package com.android.internal.util;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
@@ -25,9 +26,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.Arrays;
-import java.util.Objects;
-
@SmallTest
@RunWith(AndroidJUnit4.class)
public class RingBufferTest {
@@ -36,7 +34,7 @@
public void testEmptyRingBuffer() {
RingBuffer<String> buffer = new RingBuffer<>(String.class, 100);
- assertArraysEqual(new String[0], buffer.toArray());
+ assertArrayEquals(new String[0], buffer.toArray());
}
@Test
@@ -65,7 +63,7 @@
buffer.append("e");
String[] expected = {"a", "b", "c", "d", "e"};
- assertArraysEqual(expected, buffer.toArray());
+ assertArrayEquals(expected, buffer.toArray());
}
@Test
@@ -73,19 +71,19 @@
RingBuffer<String> buffer = new RingBuffer<>(String.class, 1);
buffer.append("a");
- assertArraysEqual(new String[]{"a"}, buffer.toArray());
+ assertArrayEquals(new String[]{"a"}, buffer.toArray());
buffer.append("b");
- assertArraysEqual(new String[]{"b"}, buffer.toArray());
+ assertArrayEquals(new String[]{"b"}, buffer.toArray());
buffer.append("c");
- assertArraysEqual(new String[]{"c"}, buffer.toArray());
+ assertArrayEquals(new String[]{"c"}, buffer.toArray());
buffer.append("d");
- assertArraysEqual(new String[]{"d"}, buffer.toArray());
+ assertArrayEquals(new String[]{"d"}, buffer.toArray());
buffer.append("e");
- assertArraysEqual(new String[]{"e"}, buffer.toArray());
+ assertArrayEquals(new String[]{"e"}, buffer.toArray());
}
@Test
@@ -100,7 +98,7 @@
buffer.append("e");
String[] expected1 = {"a", "b", "c", "d", "e"};
- assertArraysEqual(expected1, buffer.toArray());
+ assertArrayEquals(expected1, buffer.toArray());
String[] expected2 = new String[capacity];
int firstIndex = 0;
@@ -111,22 +109,22 @@
buffer.append("x");
expected2[i] = "x";
}
- assertArraysEqual(expected2, buffer.toArray());
+ assertArrayEquals(expected2, buffer.toArray());
buffer.append("x");
expected2[firstIndex] = "x";
- assertArraysEqual(expected2, buffer.toArray());
+ assertArrayEquals(expected2, buffer.toArray());
for (int i = 0; i < 10; i++) {
for (String s : expected2) {
buffer.append(s);
}
}
- assertArraysEqual(expected2, buffer.toArray());
+ assertArrayEquals(expected2, buffer.toArray());
buffer.append("a");
expected2[lastIndex] = "a";
- assertArraysEqual(expected2, buffer.toArray());
+ assertArrayEquals(expected2, buffer.toArray());
}
@Test
@@ -143,7 +141,7 @@
expected[i] = new DummyClass1();
expected[i].x = capacity * i;
}
- assertArraysEqual(expected, buffer.toArray());
+ assertArrayEquals(expected, buffer.toArray());
for (int i = 0; i < capacity; ++i) {
if (actual[i] != buffer.getNextSlot()) {
@@ -177,18 +175,4 @@
}
private static final class DummyClass3 {}
-
- static <T> void assertArraysEqual(T[] expected, T[] got) {
- if (expected.length != got.length) {
- fail(Arrays.toString(expected) + " and " + Arrays.toString(got)
- + " did not have the same length");
- }
-
- for (int i = 0; i < expected.length; i++) {
- if (!Objects.equals(expected[i], got[i])) {
- fail(Arrays.toString(expected) + " and " + Arrays.toString(got)
- + " were not equal");
- }
- }
- }
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index e3c6c41..a028a54 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -16,6 +16,9 @@
package com.android.server;
+import static android.content.pm.PackageManager.GET_PERMISSIONS;
+import static android.content.pm.PackageManager.MATCH_ANY_USER;
+import static android.net.ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.NETID_UNSET;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
@@ -25,11 +28,13 @@
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
-import static android.net.ConnectivityManager.TYPE_NONE;
import static android.net.ConnectivityManager.TYPE_WIFI;
-import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_INVALID;
-import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY;
-import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_VALID;
+import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS;
+import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_FALLBACK;
+import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTP;
+import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTPS;
+import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL;
+import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
@@ -62,11 +67,17 @@
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
import static android.net.RouteInfo.RTN_UNREACHABLE;
-import static com.android.internal.util.TestUtils.waitForIdleHandler;
-import static com.android.internal.util.TestUtils.waitForIdleLooper;
-import static com.android.internal.util.TestUtils.waitForIdleSerialExecutor;
+import static com.android.server.ConnectivityServiceTestUtilsKt.transportToLegacyType;
+import static com.android.testutils.ConcurrentUtilsKt.await;
+import static com.android.testutils.ConcurrentUtilsKt.durationOf;
+import static com.android.testutils.ExceptionUtils.ignoreExceptions;
+import static com.android.testutils.HandlerUtilsKt.waitForIdleSerialExecutor;
+import static com.android.testutils.MiscAssertsKt.assertContainsExactly;
+import static com.android.testutils.MiscAssertsKt.assertEmpty;
+import static com.android.testutils.MiscAssertsKt.assertLength;
+import static com.android.testutils.MiscAssertsKt.assertRunsInAtMost;
+import static com.android.testutils.MiscAssertsKt.assertThrows;
-import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
@@ -74,13 +85,15 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -93,6 +106,7 @@
import static org.mockito.Mockito.when;
import android.annotation.NonNull;
+import android.app.AlarmManager;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
@@ -103,6 +117,7 @@
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.net.ConnectivityManager;
@@ -112,6 +127,7 @@
import android.net.ConnectivityManager.TooManyRequestsException;
import android.net.ConnectivityThread;
import android.net.IDnsResolver;
+import android.net.IIpConnectivityMetrics;
import android.net.INetd;
import android.net.INetworkMonitor;
import android.net.INetworkMonitorCallbacks;
@@ -126,14 +142,11 @@
import android.net.LinkProperties;
import android.net.MatchAllNetworkSpecifier;
import android.net.Network;
-import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
import android.net.NetworkFactory;
-import android.net.NetworkInfo;
-import android.net.NetworkInfo.DetailedState;
-import android.net.NetworkMisc;
import android.net.NetworkRequest;
import android.net.NetworkSpecifier;
+import android.net.NetworkStack;
import android.net.NetworkStackClient;
import android.net.NetworkState;
import android.net.NetworkUtils;
@@ -146,12 +159,14 @@
import android.net.shared.NetworkMonitorUtils;
import android.net.shared.PrivateDnsConfig;
import android.net.util.MultinetworkPolicyTracker;
+import android.os.BadParcelableException;
+import android.os.Binder;
+import android.os.Bundle;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.INetworkManagementService;
import android.os.Looper;
-import android.os.Message;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
@@ -183,11 +198,16 @@
import com.android.server.connectivity.IpConnectivityMetrics;
import com.android.server.connectivity.MockableSystemProperties;
import com.android.server.connectivity.Nat464Xlat;
+import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
import com.android.server.connectivity.ProxyTracker;
import com.android.server.connectivity.Tethering;
import com.android.server.connectivity.Vpn;
import com.android.server.net.NetworkPinner;
import com.android.server.net.NetworkPolicyManagerInternal;
+import com.android.testutils.ExceptionUtils;
+import com.android.testutils.HandlerUtilsKt;
+import com.android.testutils.RecorderCallback.CallbackRecord;
+import com.android.testutils.TestableNetworkCallback;
import org.junit.After;
import org.junit.Before;
@@ -208,14 +228,12 @@
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
-import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
-import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
@@ -224,7 +242,8 @@
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.function.Predicate;
+
+import kotlin.reflect.KClass;
/**
* Tests for {@link ConnectivityService}.
@@ -244,10 +263,12 @@
// timeout. For this, our assertions should run fast enough to leave less than
// (mService.mLingerDelayMs - TEST_CALLBACK_TIMEOUT_MS) between the time callbacks are
// supposedly fired, and the time we call expectCallback.
- private final static int TEST_CALLBACK_TIMEOUT_MS = 200;
+ private static final int TEST_CALLBACK_TIMEOUT_MS = 200;
// Chosen to be less than TEST_CALLBACK_TIMEOUT_MS. This ensures that requests have time to
// complete before callbacks are verified.
- private final static int TEST_REQUEST_TIMEOUT_MS = 150;
+ private static final int TEST_REQUEST_TIMEOUT_MS = 150;
+
+ private static final int UNREASONABLY_LONG_ALARM_WAIT_MS = 1000;
private static final String CLAT_PREFIX = "v4-";
private static final String MOBILE_IFNAME = "test_rmnet_data0";
@@ -255,15 +276,19 @@
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private MockContext mServiceContext;
- private WrappedConnectivityService mService;
+ private HandlerThread mCsHandlerThread;
+ private ConnectivityService mService;
private WrappedConnectivityManager mCm;
- private MockNetworkAgent mWiFiNetworkAgent;
- private MockNetworkAgent mCellNetworkAgent;
- private MockNetworkAgent mEthernetNetworkAgent;
+ private TestNetworkAgentWrapper mWiFiNetworkAgent;
+ private TestNetworkAgentWrapper mCellNetworkAgent;
+ private TestNetworkAgentWrapper mEthernetNetworkAgent;
private MockVpn mMockVpn;
private Context mContext;
private INetworkPolicyListener mPolicyListener;
+ private WrappedMultinetworkPolicyTracker mPolicyTracker;
+ private HandlerThread mAlarmManagerThread;
+ @Mock IIpConnectivityMetrics mIpConnectivityMetrics;
@Mock IpConnectivityMetrics.Logger mMetricsService;
@Mock DefaultNetworkMetrics mDefaultNetworkMetrics;
@Mock INetworkManagementService mNetworkManagementService;
@@ -272,7 +297,10 @@
@Mock IDnsResolver mMockDnsResolver;
@Mock INetd mMockNetd;
@Mock NetworkStackClient mNetworkStack;
+ @Mock PackageManager mPackageManager;
@Mock UserManager mUserManager;
+ @Mock NotificationManager mNotificationManager;
+ @Mock AlarmManager mAlarmManager;
private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor =
ArgumentCaptor.forClass(ResolverParamsParcel.class);
@@ -342,9 +370,10 @@
@Override
public Object getSystemService(String name) {
if (Context.CONNECTIVITY_SERVICE.equals(name)) return mCm;
- if (Context.NOTIFICATION_SERVICE.equals(name)) return mock(NotificationManager.class);
+ if (Context.NOTIFICATION_SERVICE.equals(name)) return mNotificationManager;
if (Context.NETWORK_STACK_SERVICE.equals(name)) return mNetworkStack;
if (Context.USER_SERVICE.equals(name)) return mUserManager;
+ if (Context.ALARM_SERVICE.equals(name)) return mAlarmManager;
return super.getSystemService(name);
}
@@ -357,31 +386,41 @@
public Resources getResources() {
return mResources;
}
- }
- public void waitForIdle(int timeoutMsAsInt) {
- long timeoutMs = timeoutMsAsInt;
- waitForIdleHandler(mService.mHandlerThread, timeoutMs);
- waitForIdle(mCellNetworkAgent, timeoutMs);
- waitForIdle(mWiFiNetworkAgent, timeoutMs);
- waitForIdle(mEthernetNetworkAgent, timeoutMs);
- waitForIdleHandler(mService.mHandlerThread, timeoutMs);
- waitForIdleLooper(ConnectivityThread.getInstanceLooper(), timeoutMs);
- }
-
- public void waitForIdle(MockNetworkAgent agent, long timeoutMs) {
- if (agent == null) {
- return;
+ @Override
+ public PackageManager getPackageManager() {
+ return mPackageManager;
}
- waitForIdleHandler(agent.mHandlerThread, timeoutMs);
+
+ @Override
+ public void enforceCallingOrSelfPermission(String permission, String message) {
+ // The mainline permission can only be held if signed with the network stack certificate
+ // Skip testing for this permission.
+ if (NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK.equals(permission)) return;
+ // All other permissions should be held by the test or unnecessary: check as normal to
+ // make sure the code does not rely on unexpected permissions.
+ super.enforceCallingOrSelfPermission(permission, message);
+ }
}
private void waitForIdle() {
- waitForIdle(TIMEOUT_MS);
+ HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
+ waitForIdle(mCellNetworkAgent, TIMEOUT_MS);
+ waitForIdle(mWiFiNetworkAgent, TIMEOUT_MS);
+ waitForIdle(mEthernetNetworkAgent, TIMEOUT_MS);
+ HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
+ HandlerUtilsKt.waitForIdle(ConnectivityThread.get(), TIMEOUT_MS);
+ }
+
+ private void waitForIdle(TestNetworkAgentWrapper agent, long timeoutMs) {
+ if (agent == null) {
+ return;
+ }
+ agent.waitForIdle(timeoutMs);
}
@Test
- public void testWaitForIdle() {
+ public void testWaitForIdle() throws Exception {
final int attempts = 50; // Causes the test to take about 200ms on bullhead-eng.
// Tests that waitForIdle returns immediately if the service is already idle.
@@ -391,7 +430,7 @@
// Bring up a network that we can use to send messages to ConnectivityService.
ConditionVariable cv = waitForConnectivityBroadcasts(1);
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
waitFor(cv);
Network n = mWiFiNetworkAgent.getNetwork();
@@ -408,10 +447,10 @@
// This test has an inherent race condition in it, and cannot be enabled for continuous testing
// or presubmit tests. It is kept for manual runs and documentation purposes.
@Ignore
- public void verifyThatNotWaitingForIdleCausesRaceConditions() {
+ public void verifyThatNotWaitingForIdleCausesRaceConditions() throws Exception {
// Bring up a network that we can use to send messages to ConnectivityService.
ConditionVariable cv = waitForConnectivityBroadcasts(1);
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
waitFor(cv);
Network n = mWiFiNetworkAgent.getNetwork();
@@ -431,93 +470,53 @@
fail("expected race condition at least once in " + attempts + " attempts");
}
- private class MockNetworkAgent {
- private final INetworkMonitor mNetworkMonitor;
- private final NetworkInfo mNetworkInfo;
- private final NetworkCapabilities mNetworkCapabilities;
- private final HandlerThread mHandlerThread;
- private final ConditionVariable mDisconnected = new ConditionVariable();
+ private class TestNetworkAgentWrapper extends NetworkAgentWrapper {
+ private static final int VALIDATION_RESULT_BASE = NETWORK_VALIDATION_PROBE_DNS
+ | NETWORK_VALIDATION_PROBE_HTTP
+ | NETWORK_VALIDATION_PROBE_HTTPS;
+ private static final int VALIDATION_RESULT_VALID = VALIDATION_RESULT_BASE
+ | NETWORK_VALIDATION_RESULT_VALID;
+ private static final int VALIDATION_RESULT_PARTIAL = VALIDATION_RESULT_BASE
+ | NETWORK_VALIDATION_PROBE_FALLBACK
+ | NETWORK_VALIDATION_RESULT_PARTIAL;
+ private static final int VALIDATION_RESULT_INVALID = 0;
+
+ private INetworkMonitor mNetworkMonitor;
+ private INetworkMonitorCallbacks mNmCallbacks;
+ private int mNmValidationResult = VALIDATION_RESULT_BASE;
+ private String mNmValidationRedirectUrl = null;
+ private boolean mNmProvNotificationRequested = false;
+
private final ConditionVariable mNetworkStatusReceived = new ConditionVariable();
- private final ConditionVariable mPreventReconnectReceived = new ConditionVariable();
- private int mScore;
- private NetworkAgent mNetworkAgent;
- private int mStartKeepaliveError = SocketKeepalive.ERROR_UNSUPPORTED;
- private int mStopKeepaliveError = SocketKeepalive.NO_KEEPALIVE;
- private Integer mExpectedKeepaliveSlot = null;
// Contains the redirectUrl from networkStatus(). Before reading, wait for
// mNetworkStatusReceived.
private String mRedirectUrl;
- private INetworkMonitorCallbacks mNmCallbacks;
- private int mNmValidationResult = NETWORK_TEST_RESULT_INVALID;
- private String mNmValidationRedirectUrl = null;
- private boolean mNmProvNotificationRequested = false;
-
- void setNetworkValid() {
- mNmValidationResult = NETWORK_TEST_RESULT_VALID;
- mNmValidationRedirectUrl = null;
- }
-
- void setNetworkInvalid() {
- mNmValidationResult = NETWORK_TEST_RESULT_INVALID;
- mNmValidationRedirectUrl = null;
- }
-
- void setNetworkPortal(String redirectUrl) {
- setNetworkInvalid();
- mNmValidationRedirectUrl = redirectUrl;
- }
-
- void setNetworkPartial() {
- mNmValidationResult = NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY;
- mNmValidationRedirectUrl = null;
- }
-
- MockNetworkAgent(int transport) {
+ TestNetworkAgentWrapper(int transport) throws Exception {
this(transport, new LinkProperties());
}
- MockNetworkAgent(int transport, LinkProperties linkProperties) {
- final int type = transportToLegacyType(transport);
- final String typeName = ConnectivityManager.getNetworkTypeName(transport);
- mNetworkInfo = new NetworkInfo(type, 0, typeName, "Mock");
- mNetworkCapabilities = new NetworkCapabilities();
- mNetworkCapabilities.addTransportType(transport);
- switch (transport) {
- case TRANSPORT_ETHERNET:
- mScore = 70;
- break;
- case TRANSPORT_WIFI:
- mScore = 60;
- break;
- case TRANSPORT_CELLULAR:
- mScore = 50;
- break;
- case TRANSPORT_WIFI_AWARE:
- mScore = 20;
- break;
- case TRANSPORT_VPN:
- mNetworkCapabilities.removeCapability(NET_CAPABILITY_NOT_VPN);
- mScore = ConnectivityConstants.VPN_DEFAULT_SCORE;
- break;
- default:
- throw new UnsupportedOperationException("unimplemented network type");
- }
- mHandlerThread = new HandlerThread("Mock-" + typeName);
- mHandlerThread.start();
+ TestNetworkAgentWrapper(int transport, LinkProperties linkProperties)
+ throws Exception {
+ super(transport, linkProperties, mServiceContext);
+ // Waits for the NetworkAgent to be registered, which includes the creation of the
+ // NetworkMonitor.
+ waitForIdle(TIMEOUT_MS);
+ }
+
+ @Override
+ protected InstrumentedNetworkAgent makeNetworkAgent(LinkProperties linkProperties)
+ throws Exception {
mNetworkMonitor = mock(INetworkMonitor.class);
+
final Answer validateAnswer = inv -> {
- new Thread(this::onValidationRequested).start();
+ new Thread(ignoreExceptions(this::onValidationRequested)).start();
return null;
};
- try {
- doAnswer(validateAnswer).when(mNetworkMonitor).notifyNetworkConnected(any(), any());
- doAnswer(validateAnswer).when(mNetworkMonitor).forceReevaluation(anyInt());
- } catch (RemoteException e) {
- fail(e.getMessage());
- }
+ doAnswer(validateAnswer).when(mNetworkMonitor).notifyNetworkConnected(any(), any());
+ doAnswer(validateAnswer).when(mNetworkMonitor).forceReevaluation(anyInt());
final ArgumentCaptor<Network> nmNetworkCaptor = ArgumentCaptor.forClass(Network.class);
final ArgumentCaptor<INetworkMonitorCallbacks> nmCbCaptor =
@@ -527,118 +526,44 @@
any() /* name */,
nmCbCaptor.capture());
- mNetworkAgent = new NetworkAgent(mHandlerThread.getLooper(), mServiceContext,
- "Mock-" + typeName, mNetworkInfo, mNetworkCapabilities,
- linkProperties, mScore, new NetworkMisc(), NetworkFactory.SerialNumber.NONE) {
- @Override
- public void unwanted() { mDisconnected.open(); }
-
- @Override
- public void startSocketKeepalive(Message msg) {
- int slot = msg.arg1;
- if (mExpectedKeepaliveSlot != null) {
- assertEquals((int) mExpectedKeepaliveSlot, slot);
- }
- onSocketKeepaliveEvent(slot, mStartKeepaliveError);
- }
-
- @Override
- public void stopSocketKeepalive(Message msg) {
- onSocketKeepaliveEvent(msg.arg1, mStopKeepaliveError);
- }
-
+ final InstrumentedNetworkAgent na = new InstrumentedNetworkAgent(this, linkProperties) {
@Override
public void networkStatus(int status, String redirectUrl) {
mRedirectUrl = redirectUrl;
mNetworkStatusReceived.open();
}
-
- @Override
- protected void preventAutomaticReconnect() {
- mPreventReconnectReceived.open();
- }
};
- assertEquals(mNetworkAgent.netId, nmNetworkCaptor.getValue().netId);
+ assertEquals(na.netId, nmNetworkCaptor.getValue().netId);
mNmCallbacks = nmCbCaptor.getValue();
- try {
- mNmCallbacks.onNetworkMonitorCreated(mNetworkMonitor);
- } catch (RemoteException e) {
- fail(e.getMessage());
- }
+ mNmCallbacks.onNetworkMonitorCreated(mNetworkMonitor);
- // Waits for the NetworkAgent to be registered, which includes the creation of the
- // NetworkMonitor.
- waitForIdle();
+ return na;
}
- private void onValidationRequested() {
- try {
- if (mNmProvNotificationRequested
- && mNmValidationResult == NETWORK_TEST_RESULT_VALID) {
- mNmCallbacks.hideProvisioningNotification();
- mNmProvNotificationRequested = false;
- }
+ private void onValidationRequested() throws Exception {
+ if (mNmProvNotificationRequested
+ && ((mNmValidationResult & NETWORK_VALIDATION_RESULT_VALID) != 0)) {
+ mNmCallbacks.hideProvisioningNotification();
+ mNmProvNotificationRequested = false;
+ }
- mNmCallbacks.notifyNetworkTested(
- mNmValidationResult, mNmValidationRedirectUrl);
+ mNmCallbacks.notifyNetworkTested(
+ mNmValidationResult, mNmValidationRedirectUrl);
- if (mNmValidationRedirectUrl != null) {
- mNmCallbacks.showProvisioningNotification(
- "test_provisioning_notif_action", "com.android.test.package");
- mNmProvNotificationRequested = true;
- }
- } catch (RemoteException e) {
- fail(e.getMessage());
+ if (mNmValidationRedirectUrl != null) {
+ mNmCallbacks.showProvisioningNotification(
+ "test_provisioning_notif_action", "com.android.test.package");
+ mNmProvNotificationRequested = true;
}
}
- public void adjustScore(int change) {
- mScore += change;
- mNetworkAgent.sendNetworkScore(mScore);
- }
-
- public void explicitlySelected(boolean acceptUnvalidated) {
- mNetworkAgent.explicitlySelected(acceptUnvalidated);
- }
-
- public void addCapability(int capability) {
- mNetworkCapabilities.addCapability(capability);
- mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
- }
-
- public void removeCapability(int capability) {
- mNetworkCapabilities.removeCapability(capability);
- mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
- }
-
- public void setUids(Set<UidRange> uids) {
- mNetworkCapabilities.setUids(uids);
- mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
- }
-
- public void setSignalStrength(int signalStrength) {
- mNetworkCapabilities.setSignalStrength(signalStrength);
- mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
- }
-
- public void setNetworkSpecifier(NetworkSpecifier networkSpecifier) {
- mNetworkCapabilities.setNetworkSpecifier(networkSpecifier);
- mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
- }
-
- public void setNetworkCapabilities(NetworkCapabilities nc,
- boolean sendToConnectivityService) {
- mNetworkCapabilities.set(nc);
- if (sendToConnectivityService) {
- mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
- }
- }
-
+ /**
+ * Connect without adding any internet capability.
+ */
public void connectWithoutInternet() {
- mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
- mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+ super.connect();
}
/**
@@ -655,23 +580,21 @@
* @param hasInternet Indicate if network should pretend to have NET_CAPABILITY_INTERNET.
*/
public void connect(boolean validated, boolean hasInternet) {
- assertEquals("MockNetworkAgents can only be connected once",
- mNetworkInfo.getDetailedState(), DetailedState.IDLE);
- assertFalse(mNetworkCapabilities.hasCapability(NET_CAPABILITY_INTERNET));
+ assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_INTERNET));
- NetworkCallback callback = null;
+ ConnectivityManager.NetworkCallback callback = null;
final ConditionVariable validatedCv = new ConditionVariable();
if (validated) {
setNetworkValid();
NetworkRequest request = new NetworkRequest.Builder()
- .addTransportType(mNetworkCapabilities.getTransportTypes()[0])
+ .addTransportType(getNetworkCapabilities().getTransportTypes()[0])
.clearCapabilities()
.build();
- callback = new NetworkCallback() {
+ callback = new ConnectivityManager.NetworkCallback() {
public void onCapabilitiesChanged(Network network,
NetworkCapabilities networkCapabilities) {
if (network.equals(getNetwork()) &&
- networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
+ networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
validatedCv.open();
}
}
@@ -703,47 +626,34 @@
connect(false);
}
- public void suspend() {
- mNetworkInfo.setDetailedState(DetailedState.SUSPENDED, null, null);
- mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+ public void connectWithPartialValidConnectivity() {
+ setNetworkPartialValid();
+ connect(false);
}
- public void resume() {
- mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
- mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+ void setNetworkValid() {
+ mNmValidationResult = VALIDATION_RESULT_VALID;
+ mNmValidationRedirectUrl = null;
}
- public void disconnect() {
- mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
- mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+ void setNetworkInvalid() {
+ mNmValidationResult = VALIDATION_RESULT_INVALID;
+ mNmValidationRedirectUrl = null;
}
- public Network getNetwork() {
- return new Network(mNetworkAgent.netId);
+ void setNetworkPortal(String redirectUrl) {
+ setNetworkInvalid();
+ mNmValidationRedirectUrl = redirectUrl;
}
- public ConditionVariable getPreventReconnectReceived() {
- return mPreventReconnectReceived;
+ void setNetworkPartial() {
+ mNmValidationResult = VALIDATION_RESULT_PARTIAL;
+ mNmValidationRedirectUrl = null;
}
- public ConditionVariable getDisconnectedCV() {
- return mDisconnected;
- }
-
- public void sendLinkProperties(LinkProperties lp) {
- mNetworkAgent.sendLinkProperties(lp);
- }
-
- public void setStartKeepaliveError(int error) {
- mStartKeepaliveError = error;
- }
-
- public void setStopKeepaliveError(int error) {
- mStopKeepaliveError = error;
- }
-
- public void setExpectedKeepaliveSlot(Integer slot) {
- mExpectedKeepaliveSlot = slot;
+ void setNetworkPartialValid() {
+ mNmValidationResult = VALIDATION_RESULT_PARTIAL | VALIDATION_RESULT_VALID;
+ mNmValidationRedirectUrl = null;
}
public String waitForRedirectUrl() {
@@ -751,12 +661,12 @@
return mRedirectUrl;
}
- public NetworkAgent getNetworkAgent() {
- return mNetworkAgent;
+ public void expectDisconnected() {
+ expectDisconnected(TIMEOUT_MS);
}
- public NetworkCapabilities getNetworkCapabilities() {
- return mNetworkCapabilities;
+ public void expectPreventReconnectReceived() {
+ expectPreventReconnectReceived(TIMEOUT_MS);
}
}
@@ -935,15 +845,15 @@
private boolean mConnected = false;
// Careful ! This is different from mNetworkAgent, because MockNetworkAgent does
// not inherit from NetworkAgent.
- private MockNetworkAgent mMockNetworkAgent;
+ private TestNetworkAgentWrapper mMockNetworkAgent;
public MockVpn(int userId) {
super(startHandlerThreadAndReturnLooper(), mServiceContext, mNetworkManagementService,
userId);
}
- public void setNetworkAgent(MockNetworkAgent agent) {
- waitForIdle(agent, TIMEOUT_MS);
+ public void setNetworkAgent(TestNetworkAgentWrapper agent) {
+ agent.waitForIdle(TIMEOUT_MS);
mMockNetworkAgent = agent;
mNetworkAgent = agent.getNetworkAgent();
mNetworkCapabilities.set(agent.getNetworkCapabilities());
@@ -1010,192 +920,45 @@
}
}
- private class FakeWakeupMessage extends WakeupMessage {
- private static final int UNREASONABLY_LONG_WAIT = 1000;
-
- public FakeWakeupMessage(Context context, Handler handler, String cmdName, int cmd) {
- super(context, handler, cmdName, cmd);
- }
-
- public FakeWakeupMessage(Context context, Handler handler, String cmdName, int cmd,
- int arg1, int arg2, Object obj) {
- super(context, handler, cmdName, cmd, arg1, arg2, obj);
- }
-
- @Override
- public void schedule(long when) {
- long delayMs = when - SystemClock.elapsedRealtime();
- if (delayMs < 0) delayMs = 0;
- if (delayMs > UNREASONABLY_LONG_WAIT) {
- fail("Attempting to send msg more than " + UNREASONABLY_LONG_WAIT +
- "ms into the future: " + delayMs);
- }
- Message msg = mHandler.obtainMessage(mCmd, mArg1, mArg2, mObj);
- mHandler.sendMessageDelayed(msg, delayMs);
- }
-
- @Override
- public void cancel() {
- mHandler.removeMessages(mCmd, mObj);
- }
-
- @Override
- public void onAlarm() {
- throw new AssertionError("Should never happen. Update this fake.");
+ private void mockVpn(int uid) {
+ synchronized (mService.mVpns) {
+ int userId = UserHandle.getUserId(uid);
+ mMockVpn = new MockVpn(userId);
+ // This has no effect unless the VPN is actually connected, because things like
+ // getActiveNetworkForUidInternal call getNetworkAgentInfoForNetId on the VPN
+ // netId, and check if that network is actually connected.
+ mService.mVpns.put(userId, mMockVpn);
}
}
- private class WrappedMultinetworkPolicyTracker extends MultinetworkPolicyTracker {
- public volatile boolean configRestrictsAvoidBadWifi;
- public volatile int configMeteredMultipathPreference;
+ private void setUidRulesChanged(int uidRules) throws RemoteException {
+ mPolicyListener.onUidRulesChanged(Process.myUid(), uidRules);
+ }
- public WrappedMultinetworkPolicyTracker(Context c, Handler h, Runnable r) {
+ private void setRestrictBackgroundChanged(boolean restrictBackground) throws RemoteException {
+ mPolicyListener.onRestrictBackgroundChanged(restrictBackground);
+ }
+
+ private Nat464Xlat getNat464Xlat(NetworkAgentWrapper mna) {
+ return mService.getNetworkAgentInfoForNetwork(mna.getNetwork()).clatd;
+ }
+
+ private static class WrappedMultinetworkPolicyTracker extends MultinetworkPolicyTracker {
+ volatile boolean mConfigRestrictsAvoidBadWifi;
+ volatile int mConfigMeteredMultipathPreference;
+
+ WrappedMultinetworkPolicyTracker(Context c, Handler h, Runnable r) {
super(c, h, r);
}
@Override
public boolean configRestrictsAvoidBadWifi() {
- return configRestrictsAvoidBadWifi;
+ return mConfigRestrictsAvoidBadWifi;
}
@Override
public int configMeteredMultipathPreference() {
- return configMeteredMultipathPreference;
- }
- }
-
- private class WrappedConnectivityService extends ConnectivityService {
- public WrappedMultinetworkPolicyTracker wrappedMultinetworkPolicyTracker;
- private MockableSystemProperties mSystemProperties;
-
- public WrappedConnectivityService(Context context, INetworkManagementService netManager,
- INetworkStatsService statsService, INetworkPolicyManager policyManager,
- IpConnectivityLog log, INetd netd, IDnsResolver dnsResolver) {
- super(context, netManager, statsService, policyManager, dnsResolver, log, netd);
- mNetd = netd;
- mLingerDelayMs = TEST_LINGER_DELAY_MS;
- }
-
- @Override
- protected MockableSystemProperties getSystemProperties() {
- // Minimal approach to overriding system properties: let most calls fall through to real
- // device values, and only override ones values that are important to this test.
- mSystemProperties = spy(new MockableSystemProperties());
- when(mSystemProperties.getInt("net.tcp.default_init_rwnd", 0)).thenReturn(0);
- when(mSystemProperties.getBoolean("ro.radio.noril", false)).thenReturn(false);
- return mSystemProperties;
- }
-
- @Override
- protected Tethering makeTethering() {
- return mock(Tethering.class);
- }
-
- @Override
- protected ProxyTracker makeProxyTracker() {
- return mock(ProxyTracker.class);
- }
-
- @Override
- protected int reserveNetId() {
- while (true) {
- final int netId = super.reserveNetId();
-
- // Don't overlap test NetIDs with real NetIDs as binding sockets to real networks
- // can have odd side-effects, like network validations succeeding.
- Context context = InstrumentationRegistry.getContext();
- final Network[] networks = ConnectivityManager.from(context).getAllNetworks();
- boolean overlaps = false;
- for (Network network : networks) {
- if (netId == network.netId) {
- overlaps = true;
- break;
- }
- }
- if (overlaps) continue;
-
- return netId;
- }
- }
-
- @Override
- protected boolean queryUserAccess(int uid, int netId) {
- return true;
- }
-
- public Nat464Xlat getNat464Xlat(MockNetworkAgent mna) {
- return getNetworkAgentInfoForNetwork(mna.getNetwork()).clatd;
- }
-
- @Override
- public MultinetworkPolicyTracker createMultinetworkPolicyTracker(
- Context c, Handler h, Runnable r) {
- final WrappedMultinetworkPolicyTracker tracker = new WrappedMultinetworkPolicyTracker(c, h, r);
- return tracker;
- }
-
- public WrappedMultinetworkPolicyTracker getMultinetworkPolicyTracker() {
- return (WrappedMultinetworkPolicyTracker) mMultinetworkPolicyTracker;
- }
-
- @Override
- protected NetworkStackClient getNetworkStack() {
- return mNetworkStack;
- }
-
- @Override
- public WakeupMessage makeWakeupMessage(
- Context context, Handler handler, String cmdName, int cmd, Object obj) {
- return new FakeWakeupMessage(context, handler, cmdName, cmd, 0, 0, obj);
- }
-
- @Override
- public boolean hasService(String name) {
- // Currenty, the only relevant service that ConnectivityService checks for is
- // ETHERNET_SERVICE.
- return Context.ETHERNET_SERVICE.equals(name);
- }
-
- @Override
- protected IpConnectivityMetrics.Logger metricsLogger() {
- return mMetricsService;
- }
-
- @Override
- protected void registerNetdEventCallback() {
- }
-
- public void mockVpn(int uid) {
- synchronized (mVpns) {
- int userId = UserHandle.getUserId(uid);
- mMockVpn = new MockVpn(userId);
- // This has no effect unless the VPN is actually connected, because things like
- // getActiveNetworkForUidInternal call getNetworkAgentInfoForNetId on the VPN
- // netId, and check if that network is actually connected.
- mVpns.put(userId, mMockVpn);
- }
- }
-
- public void waitForIdle(int timeoutMs) {
- waitForIdleHandler(mHandlerThread, timeoutMs);
- }
-
- public void waitForIdle() {
- waitForIdle(TIMEOUT_MS);
- }
-
- public void setUidRulesChanged(int uidRules) {
- try {
- mPolicyListener.onUidRulesChanged(Process.myUid(), uidRules);
- } catch (RemoteException ignored) {
- }
- }
-
- public void setRestrictBackgroundChanged(boolean restrictBackground) {
- try {
- mPolicyListener.onRestrictBackgroundChanged(restrictBackground);
- } catch (RemoteException ignored) {
- }
+ return mConfigMeteredMultipathPreference;
}
}
@@ -1232,6 +995,7 @@
if (Looper.myLooper() == null) {
Looper.prepare();
}
+ mockDefaultPackages();
FakeSettingsProvider.clearSettingsProvider();
mServiceContext = new MockContext(InstrumentationRegistry.getContext(),
@@ -1240,13 +1004,22 @@
LocalServices.addService(
NetworkPolicyManagerInternal.class, mock(NetworkPolicyManagerInternal.class));
- mService = new WrappedConnectivityService(mServiceContext,
+ mAlarmManagerThread = new HandlerThread("TestAlarmManager");
+ mAlarmManagerThread.start();
+ initAlarmManager(mAlarmManager, mAlarmManagerThread.getThreadHandler());
+
+ mCsHandlerThread = new HandlerThread("TestConnectivityService");
+ final ConnectivityService.Dependencies deps = makeDependencies();
+ mService = new ConnectivityService(mServiceContext,
mNetworkManagementService,
mStatsService,
mNpm,
+ mMockDnsResolver,
mock(IpConnectivityLog.class),
mMockNetd,
- mMockDnsResolver);
+ deps);
+ mService.mLingerDelayMs = TEST_LINGER_DELAY_MS;
+ verify(deps).makeMultinetworkPolicyTracker(any(), any(), any());
final ArgumentCaptor<INetworkPolicyListener> policyListenerCaptor =
ArgumentCaptor.forClass(INetworkPolicyListener.class);
@@ -1257,7 +1030,7 @@
// getSystemService() correctly.
mCm = new WrappedConnectivityManager(InstrumentationRegistry.getContext(), mService);
mService.systemReady();
- mService.mockVpn(Process.myUid());
+ mockVpn(Process.myUid());
mCm.bindProcessToNetwork(null);
// Ensure that the default setting for Captive Portals is used for most tests
@@ -1266,6 +1039,57 @@
setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com");
}
+ private ConnectivityService.Dependencies makeDependencies() {
+ final MockableSystemProperties systemProperties = spy(new MockableSystemProperties());
+ when(systemProperties.getInt("net.tcp.default_init_rwnd", 0)).thenReturn(0);
+ when(systemProperties.getBoolean("ro.radio.noril", false)).thenReturn(false);
+
+ final ConnectivityService.Dependencies deps = mock(ConnectivityService.Dependencies.class);
+ doReturn(mCsHandlerThread).when(deps).makeHandlerThread();
+ doReturn(new TestNetIdManager()).when(deps).makeNetIdManager();
+ doReturn(mNetworkStack).when(deps).getNetworkStack();
+ doReturn(systemProperties).when(deps).getSystemProperties();
+ doReturn(mock(Tethering.class)).when(deps).makeTethering(any(), any(), any(), any(), any());
+ doReturn(mock(ProxyTracker.class)).when(deps).makeProxyTracker(any(), any());
+ doReturn(mMetricsService).when(deps).getMetricsLogger();
+ doReturn(true).when(deps).queryUserAccess(anyInt(), anyInt());
+ doReturn(mIpConnectivityMetrics).when(deps).getIpConnectivityMetrics();
+ doReturn(true).when(deps).hasService(Context.ETHERNET_SERVICE);
+ doAnswer(inv -> {
+ mPolicyTracker = new WrappedMultinetworkPolicyTracker(
+ inv.getArgument(0), inv.getArgument(1), inv.getArgument(2));
+ return mPolicyTracker;
+ }).when(deps).makeMultinetworkPolicyTracker(any(), any(), any());
+
+ return deps;
+ }
+
+ private static void initAlarmManager(final AlarmManager am, final Handler alarmHandler) {
+ doAnswer(inv -> {
+ final long when = inv.getArgument(1);
+ final WakeupMessage wakeupMsg = inv.getArgument(3);
+ final Handler handler = inv.getArgument(4);
+
+ long delayMs = when - SystemClock.elapsedRealtime();
+ if (delayMs < 0) delayMs = 0;
+ if (delayMs > UNREASONABLY_LONG_ALARM_WAIT_MS) {
+ fail("Attempting to send msg more than " + UNREASONABLY_LONG_ALARM_WAIT_MS
+ + "ms into the future: " + delayMs);
+ }
+ alarmHandler.postDelayed(() -> handler.post(wakeupMsg::onAlarm), wakeupMsg /* token */,
+ delayMs);
+
+ return null;
+ }).when(am).setExact(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), anyLong(), anyString(),
+ any(WakeupMessage.class), any());
+
+ doAnswer(inv -> {
+ final WakeupMessage wakeupMsg = inv.getArgument(0);
+ alarmHandler.removeCallbacksAndMessages(wakeupMsg /* token */);
+ return null;
+ }).when(am).cancel(any(WakeupMessage.class));
+ }
+
@After
public void tearDown() throws Exception {
setAlwaysOnNetworks(false);
@@ -1282,19 +1106,26 @@
mEthernetNetworkAgent = null;
}
FakeSettingsProvider.clearSettingsProvider();
+
+ mCsHandlerThread.quitSafely();
+ mAlarmManagerThread.quitSafely();
}
- private static int transportToLegacyType(int transport) {
- switch (transport) {
- case TRANSPORT_ETHERNET:
- return TYPE_ETHERNET;
- case TRANSPORT_WIFI:
- return TYPE_WIFI;
- case TRANSPORT_CELLULAR:
- return TYPE_MOBILE;
- default:
- return TYPE_NONE;
- }
+ private void mockDefaultPackages() throws Exception {
+ final String testPackageName = mContext.getPackageName();
+ final PackageInfo testPackageInfo = mContext.getPackageManager().getPackageInfo(
+ testPackageName, PackageManager.GET_PERMISSIONS);
+ when(mPackageManager.getPackagesForUid(Binder.getCallingUid())).thenReturn(
+ new String[] {testPackageName});
+ when(mPackageManager.getPackageInfoAsUser(eq(testPackageName), anyInt(),
+ eq(UserHandle.getCallingUserId()))).thenReturn(testPackageInfo);
+
+ when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
+ Arrays.asList(new PackageInfo[] {
+ buildPackageInfo(/* SYSTEM */ false, APP1_UID),
+ buildPackageInfo(/* SYSTEM */ false, APP2_UID),
+ buildPackageInfo(/* SYSTEM */ false, VPN_UID)
+ }));
}
private void verifyActiveNetwork(int transport) {
@@ -1374,8 +1205,8 @@
@Test
public void testLingering() throws Exception {
verifyNoNetwork();
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
assertNull(mCm.getActiveNetworkInfo());
assertNull(mCm.getActiveNetwork());
// Test bringing up validated cellular.
@@ -1399,7 +1230,7 @@
assertTrue(mCm.getAllNetworks()[0].equals(mCellNetworkAgent.getNetwork()) ||
mCm.getAllNetworks()[1].equals(mCellNetworkAgent.getNetwork()));
// Test cellular linger timeout.
- waitFor(mCellNetworkAgent.getDisconnectedCV());
+ mCellNetworkAgent.expectDisconnected();
waitForIdle();
assertLength(1, mCm.getAllNetworks());
verifyActiveNetwork(TRANSPORT_WIFI);
@@ -1415,13 +1246,13 @@
@Test
public void testValidatedCellularOutscoresUnvalidatedWiFi() throws Exception {
// Test bringing up unvalidated WiFi
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
ConditionVariable cv = waitForConnectivityBroadcasts(1);
mWiFiNetworkAgent.connect(false);
waitFor(cv);
verifyActiveNetwork(TRANSPORT_WIFI);
// Test bringing up unvalidated cellular
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(false);
waitForIdle();
verifyActiveNetwork(TRANSPORT_WIFI);
@@ -1430,7 +1261,7 @@
waitForIdle();
verifyActiveNetwork(TRANSPORT_WIFI);
// Test bringing up validated cellular
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
cv = waitForConnectivityBroadcasts(2);
mCellNetworkAgent.connect(true);
waitFor(cv);
@@ -1450,13 +1281,13 @@
@Test
public void testUnvalidatedWifiOutscoresUnvalidatedCellular() throws Exception {
// Test bringing up unvalidated cellular.
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
ConditionVariable cv = waitForConnectivityBroadcasts(1);
mCellNetworkAgent.connect(false);
waitFor(cv);
verifyActiveNetwork(TRANSPORT_CELLULAR);
// Test bringing up unvalidated WiFi.
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
cv = waitForConnectivityBroadcasts(2);
mWiFiNetworkAgent.connect(false);
waitFor(cv);
@@ -1476,7 +1307,7 @@
@Test
public void testUnlingeringDoesNotValidate() throws Exception {
// Test bringing up unvalidated WiFi.
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
ConditionVariable cv = waitForConnectivityBroadcasts(1);
mWiFiNetworkAgent.connect(false);
waitFor(cv);
@@ -1484,7 +1315,7 @@
assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
NET_CAPABILITY_VALIDATED));
// Test bringing up validated cellular.
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
cv = waitForConnectivityBroadcasts(2);
mCellNetworkAgent.connect(true);
waitFor(cv);
@@ -1504,13 +1335,13 @@
@Test
public void testCellularOutscoresWeakWifi() throws Exception {
// Test bringing up validated cellular.
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
ConditionVariable cv = waitForConnectivityBroadcasts(1);
mCellNetworkAgent.connect(true);
waitFor(cv);
verifyActiveNetwork(TRANSPORT_CELLULAR);
// Test bringing up validated WiFi.
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
cv = waitForConnectivityBroadcasts(2);
mWiFiNetworkAgent.connect(true);
waitFor(cv);
@@ -1531,45 +1362,41 @@
public void testReapingNetwork() throws Exception {
// Test bringing up WiFi without NET_CAPABILITY_INTERNET.
// Expect it to be torn down immediately because it satisfies no requests.
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
- ConditionVariable cv = mWiFiNetworkAgent.getDisconnectedCV();
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connectWithoutInternet();
- waitFor(cv);
+ mWiFiNetworkAgent.expectDisconnected();
// Test bringing up cellular without NET_CAPABILITY_INTERNET.
// Expect it to be torn down immediately because it satisfies no requests.
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
- cv = mCellNetworkAgent.getDisconnectedCV();
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mCellNetworkAgent.connectWithoutInternet();
- waitFor(cv);
+ mCellNetworkAgent.expectDisconnected();
// Test bringing up validated WiFi.
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
- cv = waitForConnectivityBroadcasts(1);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ final ConditionVariable cv = waitForConnectivityBroadcasts(1);
mWiFiNetworkAgent.connect(true);
waitFor(cv);
verifyActiveNetwork(TRANSPORT_WIFI);
// Test bringing up unvalidated cellular.
// Expect it to be torn down because it could never be the highest scoring network
// satisfying the default request even if it validated.
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
- cv = mCellNetworkAgent.getDisconnectedCV();
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(false);
- waitFor(cv);
+ mCellNetworkAgent.expectDisconnected();
verifyActiveNetwork(TRANSPORT_WIFI);
- cv = mWiFiNetworkAgent.getDisconnectedCV();
mWiFiNetworkAgent.disconnect();
- waitFor(cv);
+ mWiFiNetworkAgent.expectDisconnected();
}
@Test
public void testCellularFallback() throws Exception {
// Test bringing up validated cellular.
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
ConditionVariable cv = waitForConnectivityBroadcasts(1);
mCellNetworkAgent.connect(true);
waitFor(cv);
verifyActiveNetwork(TRANSPORT_CELLULAR);
// Test bringing up validated WiFi.
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
cv = waitForConnectivityBroadcasts(2);
mWiFiNetworkAgent.connect(true);
waitFor(cv);
@@ -1601,13 +1428,13 @@
@Test
public void testWiFiFallback() throws Exception {
// Test bringing up unvalidated WiFi.
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
ConditionVariable cv = waitForConnectivityBroadcasts(1);
mWiFiNetworkAgent.connect(false);
waitFor(cv);
verifyActiveNetwork(TRANSPORT_WIFI);
// Test bringing up validated cellular.
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
cv = waitForConnectivityBroadcasts(2);
mCellNetworkAgent.connect(true);
waitFor(cv);
@@ -1630,274 +1457,33 @@
mCm.getDefaultRequest().networkCapabilities));
}
- enum CallbackState {
- NONE,
- AVAILABLE,
- NETWORK_CAPABILITIES,
- LINK_PROPERTIES,
- SUSPENDED,
- RESUMED,
- LOSING,
- LOST,
- UNAVAILABLE,
- BLOCKED_STATUS
- }
-
- private static class CallbackInfo {
- public final CallbackState state;
- public final Network network;
- public final Object arg;
- public CallbackInfo(CallbackState s, Network n, Object o) {
- state = s; network = n; arg = o;
- }
- public String toString() {
- return String.format("%s (%s) (%s)", state, network, arg);
- }
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof CallbackInfo)) return false;
- // Ignore timeMs, since it's unpredictable.
- CallbackInfo other = (CallbackInfo) o;
- return (state == other.state) && Objects.equals(network, other.network);
- }
- @Override
- public int hashCode() {
- return Objects.hash(state, network);
- }
- }
-
/**
* Utility NetworkCallback for testing. The caller must explicitly test for all the callbacks
* this class receives, by calling expectCallback() exactly once each time a callback is
* received. assertNoCallback may be called at any time.
*/
- private class TestNetworkCallback extends NetworkCallback {
- private final LinkedBlockingQueue<CallbackInfo> mCallbacks = new LinkedBlockingQueue<>();
- private Network mLastAvailableNetwork;
-
- protected void setLastCallback(CallbackState state, Network network, Object o) {
- mCallbacks.offer(new CallbackInfo(state, network, o));
+ private class TestNetworkCallback extends TestableNetworkCallback {
+ @Override
+ public void assertNoCallback() {
+ // TODO: better support this use case in TestableNetworkCallback
+ waitForIdle();
+ assertNoCallback(0 /* timeout */);
}
@Override
- public void onAvailable(Network network) {
- mLastAvailableNetwork = network;
- setLastCallback(CallbackState.AVAILABLE, network, null);
- }
-
- @Override
- public void onCapabilitiesChanged(Network network, NetworkCapabilities netCap) {
- setLastCallback(CallbackState.NETWORK_CAPABILITIES, network, netCap);
- }
-
- @Override
- public void onLinkPropertiesChanged(Network network, LinkProperties linkProp) {
- setLastCallback(CallbackState.LINK_PROPERTIES, network, linkProp);
- }
-
- @Override
- public void onUnavailable() {
- setLastCallback(CallbackState.UNAVAILABLE, null, null);
- }
-
- @Override
- public void onNetworkSuspended(Network network) {
- setLastCallback(CallbackState.SUSPENDED, network, null);
- }
-
- @Override
- public void onNetworkResumed(Network network) {
- setLastCallback(CallbackState.RESUMED, network, null);
- }
-
- @Override
- public void onLosing(Network network, int maxMsToLive) {
- setLastCallback(CallbackState.LOSING, network, maxMsToLive /* autoboxed int */);
- }
-
- @Override
- public void onLost(Network network) {
- mLastAvailableNetwork = null;
- setLastCallback(CallbackState.LOST, network, null);
- }
-
- @Override
- public void onBlockedStatusChanged(Network network, boolean blocked) {
- setLastCallback(CallbackState.BLOCKED_STATUS, network, blocked);
- }
-
- public Network getLastAvailableNetwork() {
- return mLastAvailableNetwork;
- }
-
- CallbackInfo nextCallback(int timeoutMs) {
- CallbackInfo cb = null;
- try {
- cb = mCallbacks.poll(timeoutMs, TimeUnit.MILLISECONDS);
- } catch (InterruptedException e) {
- }
- if (cb == null) {
- // LinkedBlockingQueue.poll() returns null if it timeouts.
- fail("Did not receive callback after " + timeoutMs + "ms");
- }
- return cb;
- }
-
- CallbackInfo expectCallback(CallbackState state, MockNetworkAgent agent, int timeoutMs) {
- final Network expectedNetwork = (agent != null) ? agent.getNetwork() : null;
- CallbackInfo expected = new CallbackInfo(state, expectedNetwork, 0);
- CallbackInfo actual = nextCallback(timeoutMs);
- assertEquals("Unexpected callback:", expected, actual);
-
- if (state == CallbackState.LOSING) {
+ public <T extends CallbackRecord> T expectCallback(final KClass<T> type, final HasNetwork n,
+ final long timeoutMs) {
+ final T callback = super.expectCallback(type, n, timeoutMs);
+ if (callback instanceof CallbackRecord.Losing) {
+ // TODO : move this to the specific test(s) needing this rather than here.
+ final CallbackRecord.Losing losing = (CallbackRecord.Losing) callback;
+ final int maxMsToLive = losing.getMaxMsToLive();
String msg = String.format(
"Invalid linger time value %d, must be between %d and %d",
- actual.arg, 0, mService.mLingerDelayMs);
- int maxMsToLive = (Integer) actual.arg;
+ maxMsToLive, 0, mService.mLingerDelayMs);
assertTrue(msg, 0 <= maxMsToLive && maxMsToLive <= mService.mLingerDelayMs);
}
-
- return actual;
- }
-
- CallbackInfo expectCallback(CallbackState state, MockNetworkAgent agent) {
- return expectCallback(state, agent, TEST_CALLBACK_TIMEOUT_MS);
- }
-
- CallbackInfo expectCallbackLike(Predicate<CallbackInfo> fn) {
- return expectCallbackLike(fn, TEST_CALLBACK_TIMEOUT_MS);
- }
-
- CallbackInfo expectCallbackLike(Predicate<CallbackInfo> fn, int timeoutMs) {
- int timeLeft = timeoutMs;
- while (timeLeft > 0) {
- long start = SystemClock.elapsedRealtime();
- CallbackInfo info = nextCallback(timeLeft);
- if (fn.test(info)) {
- return info;
- }
- timeLeft -= (SystemClock.elapsedRealtime() - start);
- }
- fail("Did not receive expected callback after " + timeoutMs + "ms");
- return null;
- }
-
- // Expects onAvailable and the callbacks that follow it. These are:
- // - onSuspended, iff the network was suspended when the callbacks fire.
- // - onCapabilitiesChanged.
- // - onLinkPropertiesChanged.
- // - onBlockedStatusChanged.
- //
- // @param agent the network to expect the callbacks on.
- // @param expectSuspended whether to expect a SUSPENDED callback.
- // @param expectValidated the expected value of the VALIDATED capability in the
- // onCapabilitiesChanged callback.
- // @param timeoutMs how long to wait for the callbacks.
- void expectAvailableCallbacks(MockNetworkAgent agent, boolean expectSuspended,
- boolean expectValidated, boolean expectBlocked, int timeoutMs) {
- expectCallback(CallbackState.AVAILABLE, agent, timeoutMs);
- if (expectSuspended) {
- expectCallback(CallbackState.SUSPENDED, agent, timeoutMs);
- }
- if (expectValidated) {
- expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent, timeoutMs);
- } else {
- expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, agent, timeoutMs);
- }
- expectCallback(CallbackState.LINK_PROPERTIES, agent, timeoutMs);
- expectBlockedStatusCallback(expectBlocked, agent);
- }
-
- // Expects the available callbacks (validated), plus onSuspended.
- void expectAvailableAndSuspendedCallbacks(MockNetworkAgent agent, boolean expectValidated) {
- expectAvailableCallbacks(agent, true, expectValidated, false, TEST_CALLBACK_TIMEOUT_MS);
- }
-
- void expectAvailableCallbacksValidated(MockNetworkAgent agent) {
- expectAvailableCallbacks(agent, false, true, false, TEST_CALLBACK_TIMEOUT_MS);
- }
-
- void expectAvailableCallbacksValidatedAndBlocked(MockNetworkAgent agent) {
- expectAvailableCallbacks(agent, false, true, true, TEST_CALLBACK_TIMEOUT_MS);
- }
-
- void expectAvailableCallbacksUnvalidated(MockNetworkAgent agent) {
- expectAvailableCallbacks(agent, false, false, false, TEST_CALLBACK_TIMEOUT_MS);
- }
-
- void expectAvailableCallbacksUnvalidatedAndBlocked(MockNetworkAgent agent) {
- expectAvailableCallbacks(agent, false, false, true, TEST_CALLBACK_TIMEOUT_MS);
- }
-
- // Expects the available callbacks (where the onCapabilitiesChanged must contain the
- // VALIDATED capability), plus another onCapabilitiesChanged which is identical to the
- // one we just sent.
- // TODO: this is likely a bug. Fix it and remove this method.
- void expectAvailableDoubleValidatedCallbacks(MockNetworkAgent agent) {
- expectCallback(CallbackState.AVAILABLE, agent, TEST_CALLBACK_TIMEOUT_MS);
- NetworkCapabilities nc1 = expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent);
- expectCallback(CallbackState.LINK_PROPERTIES, agent, TEST_CALLBACK_TIMEOUT_MS);
- // Implicitly check the network is allowed to use.
- // TODO: should we need to consider if network is in blocked status in this case?
- expectBlockedStatusCallback(false, agent);
- NetworkCapabilities nc2 = expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent);
- assertEquals(nc1, nc2);
- }
-
- // Expects the available callbacks where the onCapabilitiesChanged must not have validated,
- // then expects another onCapabilitiesChanged that has the validated bit set. This is used
- // when a network connects and satisfies a callback, and then immediately validates.
- void expectAvailableThenValidatedCallbacks(MockNetworkAgent agent) {
- expectAvailableCallbacksUnvalidated(agent);
- expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent);
- }
-
- NetworkCapabilities expectCapabilitiesWith(int capability, MockNetworkAgent agent) {
- return expectCapabilitiesWith(capability, agent, TEST_CALLBACK_TIMEOUT_MS);
- }
-
- NetworkCapabilities expectCapabilitiesWith(int capability, MockNetworkAgent agent,
- int timeoutMs) {
- CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent, timeoutMs);
- NetworkCapabilities nc = (NetworkCapabilities) cbi.arg;
- assertTrue(nc.hasCapability(capability));
- return nc;
- }
-
- NetworkCapabilities expectCapabilitiesWithout(int capability, MockNetworkAgent agent) {
- return expectCapabilitiesWithout(capability, agent, TEST_CALLBACK_TIMEOUT_MS);
- }
-
- NetworkCapabilities expectCapabilitiesWithout(int capability, MockNetworkAgent agent,
- int timeoutMs) {
- CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent, timeoutMs);
- NetworkCapabilities nc = (NetworkCapabilities) cbi.arg;
- assertFalse(nc.hasCapability(capability));
- return nc;
- }
-
- void expectCapabilitiesLike(Predicate<NetworkCapabilities> fn, MockNetworkAgent agent) {
- CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent);
- assertTrue("Received capabilities don't match expectations : " + cbi.arg,
- fn.test((NetworkCapabilities) cbi.arg));
- }
-
- void expectLinkPropertiesLike(Predicate<LinkProperties> fn, MockNetworkAgent agent) {
- CallbackInfo cbi = expectCallback(CallbackState.LINK_PROPERTIES, agent);
- assertTrue("Received LinkProperties don't match expectations : " + cbi.arg,
- fn.test((LinkProperties) cbi.arg));
- }
-
- void expectBlockedStatusCallback(boolean expectBlocked, MockNetworkAgent agent) {
- CallbackInfo cbi = expectCallback(CallbackState.BLOCKED_STATUS, agent);
- boolean actualBlocked = (boolean) cbi.arg;
- assertEquals(expectBlocked, actualBlocked);
- }
-
- void assertNoCallback() {
- waitForIdle();
- CallbackInfo c = mCallbacks.peek();
- assertNull("Unexpected callback: " + c, c);
+ return callback;
}
}
@@ -1926,7 +1512,7 @@
// Test unvalidated networks
ConditionVariable cv = waitForConnectivityBroadcasts(1);
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(false);
genericNetworkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
cellNetworkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
@@ -1941,7 +1527,7 @@
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
cv = waitForConnectivityBroadcasts(2);
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -1951,21 +1537,21 @@
cv = waitForConnectivityBroadcasts(2);
mWiFiNetworkAgent.disconnect();
- genericNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- wifiNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ genericNetworkCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ wifiNetworkCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
cellNetworkCallback.assertNoCallback();
waitFor(cv);
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
cv = waitForConnectivityBroadcasts(1);
mCellNetworkAgent.disconnect();
- genericNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ genericNetworkCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
waitFor(cv);
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
// Test validated networks
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
genericNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
@@ -1978,29 +1564,29 @@
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- genericNetworkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ genericNetworkCallback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
genericNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
wifiNetworkCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
mWiFiNetworkAgent.disconnect();
- genericNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- wifiNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ genericNetworkCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ wifiNetworkCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
mCellNetworkAgent.disconnect();
- genericNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ genericNetworkCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
}
@Test
- public void testMultipleLingering() {
+ public void testMultipleLingering() throws Exception {
// This test would be flaky with the default 120ms timer: that is short enough that
// lingered networks are torn down before assertions can be run. We don't want to mock the
// lingering timer to keep the WakeupMessage logic realistic: this has already proven useful
@@ -2016,9 +1602,9 @@
TestNetworkCallback defaultCallback = new TestNetworkCallback();
mCm.registerDefaultNetworkCallback(defaultCallback);
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
- mEthernetNetworkAgent = new MockNetworkAgent(TRANSPORT_ETHERNET);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
@@ -2035,7 +1621,7 @@
// We then get LOSING when wifi validates and cell is outscored.
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
// TODO: Investigate sending validated before losing.
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
@@ -2044,20 +1630,20 @@
mEthernetNetworkAgent.connect(true);
callback.expectAvailableCallbacksUnvalidated(mEthernetNetworkAgent);
// TODO: Investigate sending validated before losing.
- callback.expectCallback(CallbackState.LOSING, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mWiFiNetworkAgent);
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
defaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
mEthernetNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
- defaultCallback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mEthernetNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mEthernetNetworkAgent);
defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
for (int i = 0; i < 4; i++) {
- MockNetworkAgent oldNetwork, newNetwork;
+ TestNetworkAgentWrapper oldNetwork, newNetwork;
if (i % 2 == 0) {
mWiFiNetworkAgent.adjustScore(-15);
oldNetwork = mWiFiNetworkAgent;
@@ -2068,7 +1654,7 @@
newNetwork = mWiFiNetworkAgent;
}
- callback.expectCallback(CallbackState.LOSING, oldNetwork);
+ callback.expectCallback(CallbackRecord.LOSING, oldNetwork);
// TODO: should we send an AVAILABLE callback to newNetwork, to indicate that it is no
// longer lingering?
defaultCallback.expectAvailableCallbacksValidated(newNetwork);
@@ -2082,7 +1668,7 @@
// We expect a notification about the capabilities change, and nothing else.
defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED, mWiFiNetworkAgent);
defaultCallback.assertNoCallback();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Wifi no longer satisfies our listen, which is for an unmetered network.
@@ -2091,11 +1677,11 @@
// Disconnect our test networks.
mWiFiNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
mCellNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
waitForIdle();
assertEquals(null, mCm.getActiveNetwork());
@@ -2109,7 +1695,7 @@
mCm.registerNetworkCallback(request, callback);
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(false); // Score: 10
callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
@@ -2118,7 +1704,7 @@
// Bring up wifi with a score of 20.
// Cell stays up because it would satisfy the default request if it validated.
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false); // Score: 20
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -2126,65 +1712,65 @@
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Bring up wifi with a score of 70.
// Cell is lingered because it would not satisfy any request, even if it validated.
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.adjustScore(50);
mWiFiNetworkAgent.connect(false); // Score: 70
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Tear down wifi.
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Bring up wifi, then validate it. Previous versions would immediately tear down cell, but
// it's arguably correct to linger it, since it was the default network before it validated.
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
// TODO: Investigate sending validated before losing.
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
mCellNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
waitForIdle();
assertEquals(null, mCm.getActiveNetwork());
// If a network is lingering, and we add and remove a request from it, resume lingering.
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
// TODO: Investigate sending validated before losing.
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
@@ -2195,13 +1781,13 @@
// TODO: should this cause an AVAILABLE callback, to indicate that the network is no longer
// lingering?
mCm.unregisterNetworkCallback(noopCallback);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
// Similar to the above: lingering can start even after the lingered request is removed.
// Disconnect wifi and switch to cell.
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
@@ -2210,7 +1796,7 @@
mCm.requestNetwork(cellRequest, noopCallback);
// Now connect wifi, and expect it to become the default network.
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
callback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
@@ -2220,34 +1806,34 @@
callback.assertNoCallback();
// Now unregister cellRequest and expect cell to start lingering.
mCm.unregisterNetworkCallback(noopCallback);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
// Let linger run its course.
callback.assertNoCallback();
final int lingerTimeoutMs = mService.mLingerDelayMs + mService.mLingerDelayMs / 4;
- callback.expectCallback(CallbackState.LOST, mCellNetworkAgent, lingerTimeoutMs);
+ callback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent, lingerTimeoutMs);
// Register a TRACK_DEFAULT request and check that it does not affect lingering.
TestNetworkCallback trackDefaultCallback = new TestNetworkCallback();
mCm.registerDefaultNetworkCallback(trackDefaultCallback);
trackDefaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
- mEthernetNetworkAgent = new MockNetworkAgent(TRANSPORT_ETHERNET);
+ mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
mEthernetNetworkAgent.connect(true);
callback.expectAvailableCallbacksUnvalidated(mEthernetNetworkAgent);
- callback.expectCallback(CallbackState.LOSING, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mWiFiNetworkAgent);
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
trackDefaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
defaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Let linger run its course.
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent, lingerTimeoutMs);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent, lingerTimeoutMs);
// Clean up.
mEthernetNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
- defaultCallback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
- trackDefaultCallback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mEthernetNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mEthernetNetworkAgent);
+ trackDefaultCallback.expectCallback(CallbackRecord.LOST, mEthernetNetworkAgent);
mCm.unregisterNetworkCallback(callback);
mCm.unregisterNetworkCallback(defaultCallback);
@@ -2255,7 +1841,7 @@
}
@Test
- public void testNetworkGoesIntoBackgroundAfterLinger() {
+ public void testNetworkGoesIntoBackgroundAfterLinger() throws Exception {
setAlwaysOnNetworks(true);
NetworkRequest request = new NetworkRequest.Builder()
.clearCapabilities()
@@ -2266,8 +1852,8 @@
TestNetworkCallback defaultCallback = new TestNetworkCallback();
mCm.registerDefaultNetworkCallback(defaultCallback);
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mCellNetworkAgent.connect(true);
callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
@@ -2277,7 +1863,7 @@
mWiFiNetworkAgent.connect(true);
defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
// File a request for cellular, then release it.
@@ -2286,7 +1872,7 @@
NetworkCallback noopCallback = new NetworkCallback();
mCm.requestNetwork(cellRequest, noopCallback);
mCm.unregisterNetworkCallback(noopCallback);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
// Let linger run its course.
callback.assertNoCallback();
@@ -2300,7 +1886,7 @@
}
@Test
- public void testExplicitlySelected() {
+ public void testExplicitlySelected() throws Exception {
NetworkRequest request = new NetworkRequest.Builder()
.clearCapabilities().addCapability(NET_CAPABILITY_INTERNET)
.build();
@@ -2308,13 +1894,13 @@
mCm.registerNetworkCallback(request, callback);
// Bring up validated cell.
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
// Bring up unvalidated wifi with explicitlySelected=true.
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
- mWiFiNetworkAgent.explicitlySelected(false);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.explicitlySelected(true, false);
mWiFiNetworkAgent.connect(false);
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -2330,47 +1916,69 @@
// If the user chooses yes on the "No Internet access, stay connected?" dialog, we switch to
// wifi even though it's unvalidated.
mCm.setAcceptUnvalidated(mWiFiNetworkAgent.getNetwork(), true, false);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
// Disconnect wifi, and then reconnect, again with explicitlySelected=true.
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
- mWiFiNetworkAgent.explicitlySelected(false);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.explicitlySelected(true, false);
mWiFiNetworkAgent.connect(false);
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
// If the user chooses no on the "No Internet access, stay connected?" dialog, we ask the
// network to disconnect.
mCm.setAcceptUnvalidated(mWiFiNetworkAgent.getNetwork(), false, false);
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
// Reconnect, again with explicitlySelected=true, but this time validate.
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
- mWiFiNetworkAgent.explicitlySelected(false);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.explicitlySelected(true, false);
mWiFiNetworkAgent.connect(true);
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
// BUG: the network will no longer linger, even though it's validated and outscored.
// TODO: fix this.
- mEthernetNetworkAgent = new MockNetworkAgent(TRANSPORT_ETHERNET);
+ mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
mEthernetNetworkAgent.connect(true);
callback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent);
assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork());
callback.assertNoCallback();
+ // Disconnect wifi, and then reconnect as if the user had selected "yes, don't ask again"
+ // (i.e., with explicitlySelected=true and acceptUnvalidated=true). Expect to switch to
+ // wifi immediately.
+ mWiFiNetworkAgent.disconnect();
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.explicitlySelected(true, true);
+ mWiFiNetworkAgent.connect(false);
+ callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mEthernetNetworkAgent);
+ assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ mEthernetNetworkAgent.disconnect();
+ callback.expectCallback(CallbackRecord.LOST, mEthernetNetworkAgent);
+
+ // Disconnect and reconnect with explicitlySelected=false and acceptUnvalidated=true.
+ // Check that the network is not scored specially and that the device prefers cell data.
+ mWiFiNetworkAgent.disconnect();
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.explicitlySelected(false, true);
+ mWiFiNetworkAgent.connect(false);
+ callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+
// Clean up.
mWiFiNetworkAgent.disconnect();
mCellNetworkAgent.disconnect();
- mEthernetNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- callback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
- callback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
}
private int[] makeIntArray(final int size, final int value) {
@@ -2421,7 +2029,7 @@
assertTrue(testFactory.getMyStartRequested());
// Now bring in a higher scored network.
- MockNetworkAgent testAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ TestNetworkAgentWrapper testAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
// Rather than create a validated network which complicates things by registering it's
// own NetworkRequest during startup, just bump up the score to cancel out the
// unvalidated penalty.
@@ -2506,27 +2114,26 @@
.build();
Class<IllegalArgumentException> expected = IllegalArgumentException.class;
- assertException(() -> { mCm.requestNetwork(request1, new NetworkCallback()); }, expected);
- assertException(() -> { mCm.requestNetwork(request1, pendingIntent); }, expected);
- assertException(() -> { mCm.requestNetwork(request2, new NetworkCallback()); }, expected);
- assertException(() -> { mCm.requestNetwork(request2, pendingIntent); }, expected);
+ assertThrows(expected, () -> mCm.requestNetwork(request1, new NetworkCallback()));
+ assertThrows(expected, () -> mCm.requestNetwork(request1, pendingIntent));
+ assertThrows(expected, () -> mCm.requestNetwork(request2, new NetworkCallback()));
+ assertThrows(expected, () -> mCm.requestNetwork(request2, pendingIntent));
}
@Test
public void testMMSonWiFi() throws Exception {
// Test bringing up cellular without MMS NetworkRequest gets reaped
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS);
- ConditionVariable cv = mCellNetworkAgent.getDisconnectedCV();
mCellNetworkAgent.connectWithoutInternet();
- waitFor(cv);
+ mCellNetworkAgent.expectDisconnected();
waitForIdle();
assertEmpty(mCm.getAllNetworks());
verifyNoNetwork();
// Test bringing up validated WiFi.
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
- cv = waitForConnectivityBroadcasts(1);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ final ConditionVariable cv = waitForConnectivityBroadcasts(1);
mWiFiNetworkAgent.connect(true);
waitFor(cv);
verifyActiveNetwork(TRANSPORT_WIFI);
@@ -2538,23 +2145,22 @@
mCm.requestNetwork(builder.build(), networkCallback);
// Test bringing up unvalidated cellular with MMS
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS);
mCellNetworkAgent.connectWithoutInternet();
networkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
verifyActiveNetwork(TRANSPORT_WIFI);
// Test releasing NetworkRequest disconnects cellular with MMS
- cv = mCellNetworkAgent.getDisconnectedCV();
mCm.unregisterNetworkCallback(networkCallback);
- waitFor(cv);
+ mCellNetworkAgent.expectDisconnected();
verifyActiveNetwork(TRANSPORT_WIFI);
}
@Test
public void testMMSonCell() throws Exception {
// Test bringing up cellular without MMS
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
ConditionVariable cv = waitForConnectivityBroadcasts(1);
mCellNetworkAgent.connect(false);
waitFor(cv);
@@ -2567,21 +2173,21 @@
mCm.requestNetwork(builder.build(), networkCallback);
// Test bringing up MMS cellular network
- MockNetworkAgent mmsNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ TestNetworkAgentWrapper
+ mmsNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mmsNetworkAgent.addCapability(NET_CAPABILITY_MMS);
mmsNetworkAgent.connectWithoutInternet();
networkCallback.expectAvailableCallbacksUnvalidated(mmsNetworkAgent);
verifyActiveNetwork(TRANSPORT_CELLULAR);
// Test releasing MMS NetworkRequest does not disconnect main cellular NetworkAgent
- cv = mmsNetworkAgent.getDisconnectedCV();
mCm.unregisterNetworkCallback(networkCallback);
- waitFor(cv);
+ mmsNetworkAgent.expectDisconnected();
verifyActiveNetwork(TRANSPORT_CELLULAR);
}
@Test
- public void testPartialConnectivity() {
+ public void testPartialConnectivity() throws Exception {
// Register network callback.
NetworkRequest request = new NetworkRequest.Builder()
.clearCapabilities().addCapability(NET_CAPABILITY_INTERNET)
@@ -2590,12 +2196,12 @@
mCm.registerNetworkCallback(request, callback);
// Bring up validated mobile data.
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
// Bring up wifi with partial connectivity.
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connectWithPartialConnectivity();
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiNetworkAgent);
@@ -2606,7 +2212,7 @@
// With HTTPS probe disabled, NetworkMonitor should pass the network validation with http
// probe.
- mWiFiNetworkAgent.setNetworkValid();
+ mWiFiNetworkAgent.setNetworkPartialValid();
// If the user chooses yes to use this partial connectivity wifi, switch the default
// network to wifi and check if wifi becomes valid or not.
mCm.setAcceptPartialConnectivity(mWiFiNetworkAgent.getNetwork(), true /* accept */,
@@ -2614,15 +2220,12 @@
// If user accepts partial connectivity network,
// NetworkMonitor#setAcceptPartialConnectivity() should be called too.
waitForIdle();
- try {
- verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
- } catch (RemoteException e) {
- fail(e.getMessage());
- }
+ verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
+
// Need a trigger point to let NetworkMonitor tell ConnectivityService that network is
// validated.
mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
NetworkCapabilities nc = callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED,
mWiFiNetworkAgent);
assertTrue(nc.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY));
@@ -2630,8 +2233,8 @@
// Disconnect and reconnect wifi with partial connectivity again.
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connectWithPartialConnectivity();
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiNetworkAgent);
@@ -2642,69 +2245,79 @@
// If the user chooses no, disconnect wifi immediately.
mCm.setAcceptPartialConnectivity(mWiFiNetworkAgent.getNetwork(), false/* accept */,
false /* always */);
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
// If user accepted partial connectivity before, and device reconnects to that network
// again, but now the network has full connectivity. The network shouldn't contain
// NET_CAPABILITY_PARTIAL_CONNECTIVITY.
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
// acceptUnvalidated is also used as setting for accepting partial networks.
- mWiFiNetworkAgent.explicitlySelected(true /* acceptUnvalidated */);
+ mWiFiNetworkAgent.explicitlySelected(true /* explicitlySelected */,
+ true /* acceptUnvalidated */);
mWiFiNetworkAgent.connect(true);
+
// If user accepted partial connectivity network before,
// NetworkMonitor#setAcceptPartialConnectivity() will be called in
// ConnectivityService#updateNetworkInfo().
waitForIdle();
- try {
- verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
- } catch (RemoteException e) {
- fail(e.getMessage());
- }
+ verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
nc = callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
assertFalse(nc.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY));
+
// Wifi should be the default network.
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
- // If user accepted partial connectivity before, and now the device reconnects to the
- // partial connectivity network. The network should be valid and contain
- // NET_CAPABILITY_PARTIAL_CONNECTIVITY.
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
- mWiFiNetworkAgent.explicitlySelected(true /* acceptUnvalidated */);
- // Current design cannot send multi-testResult from NetworkMonitor to ConnectivityService.
- // So, if user accepts partial connectivity, NetworkMonitor will send PARTIAL_CONNECTIVITY
- // to ConnectivityService first then send VALID. Once NetworkMonitor support
- // multi-testResult, this test case also need to be changed to meet the new design.
+ // The user accepted partial connectivity and selected "don't ask again". Now the user
+ // reconnects to the partial connectivity network. Switch to wifi as soon as partial
+ // connectivity is detected.
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.explicitlySelected(true /* explicitlySelected */,
+ true /* acceptUnvalidated */);
mWiFiNetworkAgent.connectWithPartialConnectivity();
// If user accepted partial connectivity network before,
// NetworkMonitor#setAcceptPartialConnectivity() will be called in
// ConnectivityService#updateNetworkInfo().
waitForIdle();
- try {
- verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
- } catch (RemoteException e) {
- fail(e.getMessage());
- }
+ verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
- // TODO: If the user accepted partial connectivity, we shouldn't switch to wifi until
- // NetworkMonitor detects partial connectivity
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiNetworkAgent);
mWiFiNetworkAgent.setNetworkValid();
+
// Need a trigger point to let NetworkMonitor tell ConnectivityService that network is
// validated.
mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+
+ // If the user accepted partial connectivity, and the device auto-reconnects to the partial
+ // connectivity network, it should contain both PARTIAL_CONNECTIVITY and VALIDATED.
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.explicitlySelected(false /* explicitlySelected */,
+ true /* acceptUnvalidated */);
+
+ // NetworkMonitor will immediately (once the HTTPS probe fails...) report the network as
+ // valid, because ConnectivityService calls setAcceptPartialConnectivity before it calls
+ // notifyNetworkConnected.
+ mWiFiNetworkAgent.connectWithPartialValidConnectivity();
+ waitForIdle();
+ verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
+ callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
+ callback.expectCapabilitiesWith(
+ NET_CAPABILITY_PARTIAL_CONNECTIVITY | NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+ mWiFiNetworkAgent.disconnect();
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
}
@Test
- public void testCaptivePortal() {
+ public void testCaptivePortalOnPartialConnectivity() throws Exception {
final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
.addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
@@ -2717,7 +2330,56 @@
// Bring up a network with a captive portal.
// Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ String redirectUrl = "http://android.com/path";
+ mWiFiNetworkAgent.connectWithCaptivePortal(redirectUrl);
+ captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), redirectUrl);
+
+ // Check that startCaptivePortalApp sends the expected command to NetworkMonitor.
+ mCm.startCaptivePortalApp(mWiFiNetworkAgent.getNetwork());
+ verify(mWiFiNetworkAgent.mNetworkMonitor, timeout(TIMEOUT_MS).times(1))
+ .launchCaptivePortalApp();
+
+ // Report that the captive portal is dismissed with partial connectivity, and check that
+ // callbacks are fired.
+ mWiFiNetworkAgent.setNetworkPartial();
+ mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
+ waitForIdle();
+ captivePortalCallback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY,
+ mWiFiNetworkAgent);
+
+ // Report partial connectivity is accepted.
+ mWiFiNetworkAgent.setNetworkPartialValid();
+ mCm.setAcceptPartialConnectivity(mWiFiNetworkAgent.getNetwork(), true /* accept */,
+ false /* always */);
+ waitForIdle();
+ mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
+ captivePortalCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ validatedCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
+ NetworkCapabilities nc =
+ validatedCallback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY,
+ mWiFiNetworkAgent);
+
+ mCm.unregisterNetworkCallback(captivePortalCallback);
+ mCm.unregisterNetworkCallback(validatedCallback);
+ }
+
+ @Test
+ public void testCaptivePortal() throws Exception {
+ final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
+ final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
+ .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
+ mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback);
+
+ final TestNetworkCallback validatedCallback = new TestNetworkCallback();
+ final NetworkRequest validatedRequest = new NetworkRequest.Builder()
+ .addCapability(NET_CAPABILITY_VALIDATED).build();
+ mCm.registerNetworkCallback(validatedRequest, validatedCallback);
+
+ // Bring up a network with a captive portal.
+ // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
String firstRedirectUrl = "http://example.com/firstPath";
mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl);
captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -2726,11 +2388,11 @@
// Take down network.
// Expect onLost callback.
mWiFiNetworkAgent.disconnect();
- captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ captivePortalCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
// Bring up a network with a captive portal.
// Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
String secondRedirectUrl = "http://example.com/secondPath";
mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl);
captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -2740,20 +2402,23 @@
// Expect onLost callback because network no longer provides NET_CAPABILITY_CAPTIVE_PORTAL.
mWiFiNetworkAgent.setNetworkValid();
mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
- captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ captivePortalCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
// Expect NET_CAPABILITY_VALIDATED onAvailable callback.
validatedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
+ // Expect no notification to be shown when captive portal disappears by itself
+ verify(mNotificationManager, never()).notifyAsUser(
+ anyString(), eq(NotificationType.LOGGED_IN.eventId), any(), any());
// Break network connectivity.
// Expect NET_CAPABILITY_VALIDATED onLost callback.
mWiFiNetworkAgent.setNetworkInvalid();
mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false);
- validatedCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ validatedCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
}
@Test
- public void testCaptivePortalApp() throws RemoteException {
+ public void testCaptivePortalApp() throws Exception {
final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
.addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
@@ -2765,7 +2430,7 @@
mCm.registerNetworkCallback(validatedRequest, validatedCallback);
// Bring up wifi.
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
validatedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
@@ -2773,31 +2438,45 @@
// Check that calling startCaptivePortalApp does nothing.
final int fastTimeoutMs = 100;
mCm.startCaptivePortalApp(wifiNetwork);
+ waitForIdle();
+ verify(mWiFiNetworkAgent.mNetworkMonitor, never()).launchCaptivePortalApp();
mServiceContext.expectNoStartActivityIntent(fastTimeoutMs);
// Turn into a captive portal.
mWiFiNetworkAgent.setNetworkPortal("http://example.com");
mCm.reportNetworkConnectivity(wifiNetwork, false);
captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- validatedCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ validatedCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
// Check that startCaptivePortalApp sends the expected command to NetworkMonitor.
mCm.startCaptivePortalApp(wifiNetwork);
- verify(mWiFiNetworkAgent.mNetworkMonitor, timeout(TIMEOUT_MS).times(1))
- .launchCaptivePortalApp();
+ waitForIdle();
+ verify(mWiFiNetworkAgent.mNetworkMonitor).launchCaptivePortalApp();
+
+ // NetworkMonitor uses startCaptivePortal(Network, Bundle) (startCaptivePortalAppInternal)
+ final Bundle testBundle = new Bundle();
+ final String testKey = "testkey";
+ final String testValue = "testvalue";
+ testBundle.putString(testKey, testValue);
+ mCm.startCaptivePortalApp(wifiNetwork, testBundle);
+ final Intent signInIntent = mServiceContext.expectStartActivityIntent(TIMEOUT_MS);
+ assertEquals(ACTION_CAPTIVE_PORTAL_SIGN_IN, signInIntent.getAction());
+ assertEquals(testValue, signInIntent.getStringExtra(testKey));
// Report that the captive portal is dismissed, and check that callbacks are fired
mWiFiNetworkAgent.setNetworkValid();
mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
validatedCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
- captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ captivePortalCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ verify(mNotificationManager, times(1)).notifyAsUser(anyString(),
+ eq(NotificationType.LOGGED_IN.eventId), any(), eq(UserHandle.ALL));
mCm.unregisterNetworkCallback(validatedCallback);
mCm.unregisterNetworkCallback(captivePortalCallback);
}
@Test
- public void testAvoidOrIgnoreCaptivePortals() {
+ public void testAvoidOrIgnoreCaptivePortals() throws Exception {
final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
.addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
@@ -2811,14 +2490,12 @@
setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_AVOID);
// Bring up a network with a captive portal.
// Expect it to fail to connect and not result in any callbacks.
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
String firstRedirectUrl = "http://example.com/firstPath";
- ConditionVariable disconnectCv = mWiFiNetworkAgent.getDisconnectedCV();
- ConditionVariable avoidCv = mWiFiNetworkAgent.getPreventReconnectReceived();
mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl);
- waitFor(disconnectCv);
- waitFor(avoidCv);
+ mWiFiNetworkAgent.expectDisconnected();
+ mWiFiNetworkAgent.expectPreventReconnectReceived();
assertNoCallbacks(captivePortalCallback, validatedCallback);
}
@@ -2837,7 +2514,7 @@
* does work.
*/
@Test
- public void testNetworkSpecifier() {
+ public void testNetworkSpecifier() throws Exception {
// A NetworkSpecifier subclass that matches all networks but must not be visible to apps.
class ConfidentialMatchAllNetworkSpecifier extends NetworkSpecifier implements
Parcelable {
@@ -2917,7 +2594,7 @@
LocalStringNetworkSpecifier nsFoo = new LocalStringNetworkSpecifier("foo");
LocalStringNetworkSpecifier nsBar = new LocalStringNetworkSpecifier("bar");
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
cEmpty1.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
cEmpty2.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -2928,24 +2605,24 @@
mWiFiNetworkAgent.setNetworkSpecifier(nsFoo);
cFoo.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
for (TestNetworkCallback c: emptyCallbacks) {
- c.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier().equals(nsFoo),
- mWiFiNetworkAgent);
+ c.expectCapabilitiesThat(mWiFiNetworkAgent,
+ (caps) -> caps.getNetworkSpecifier().equals(nsFoo));
}
- cFoo.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier().equals(nsFoo),
- mWiFiNetworkAgent);
+ cFoo.expectCapabilitiesThat(mWiFiNetworkAgent,
+ (caps) -> caps.getNetworkSpecifier().equals(nsFoo));
assertEquals(nsFoo,
mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).getNetworkSpecifier());
cFoo.assertNoCallback();
mWiFiNetworkAgent.setNetworkSpecifier(nsBar);
- cFoo.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ cFoo.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
cBar.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
for (TestNetworkCallback c: emptyCallbacks) {
- c.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier().equals(nsBar),
- mWiFiNetworkAgent);
+ c.expectCapabilitiesThat(mWiFiNetworkAgent,
+ (caps) -> caps.getNetworkSpecifier().equals(nsBar));
}
- cBar.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier().equals(nsBar),
- mWiFiNetworkAgent);
+ cBar.expectCapabilitiesThat(mWiFiNetworkAgent,
+ (caps) -> caps.getNetworkSpecifier().equals(nsBar));
assertEquals(nsBar,
mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).getNetworkSpecifier());
cBar.assertNoCallback();
@@ -2953,23 +2630,23 @@
mWiFiNetworkAgent.setNetworkSpecifier(new ConfidentialMatchAllNetworkSpecifier());
cFoo.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
for (TestNetworkCallback c : emptyCallbacks) {
- c.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier() == null,
- mWiFiNetworkAgent);
+ c.expectCapabilitiesThat(mWiFiNetworkAgent,
+ (caps) -> caps.getNetworkSpecifier() == null);
}
- cFoo.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier() == null,
- mWiFiNetworkAgent);
- cBar.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier() == null,
- mWiFiNetworkAgent);
+ cFoo.expectCapabilitiesThat(mWiFiNetworkAgent,
+ (caps) -> caps.getNetworkSpecifier() == null);
+ cBar.expectCapabilitiesThat(mWiFiNetworkAgent,
+ (caps) -> caps.getNetworkSpecifier() == null);
assertNull(
mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).getNetworkSpecifier());
cFoo.assertNoCallback();
cBar.assertNoCallback();
mWiFiNetworkAgent.setNetworkSpecifier(null);
- cFoo.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- cBar.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ cFoo.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ cBar.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
for (TestNetworkCallback c: emptyCallbacks) {
- c.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent);
+ c.expectCallback(CallbackRecord.NETWORK_CAPS_UPDATED, mWiFiNetworkAgent);
}
assertNoCallbacks(cEmpty1, cEmpty2, cEmpty3, cEmpty4, cFoo, cBar);
@@ -2977,24 +2654,18 @@
@Test
public void testInvalidNetworkSpecifier() {
- try {
+ assertThrows(IllegalArgumentException.class, () -> {
NetworkRequest.Builder builder = new NetworkRequest.Builder();
builder.setNetworkSpecifier(new MatchAllNetworkSpecifier());
- fail("NetworkRequest builder with MatchAllNetworkSpecifier");
- } catch (IllegalArgumentException expected) {
- // expected
- }
+ });
- try {
+ assertThrows(IllegalArgumentException.class, () -> {
NetworkCapabilities networkCapabilities = new NetworkCapabilities();
networkCapabilities.addTransportType(TRANSPORT_WIFI)
.setNetworkSpecifier(new MatchAllNetworkSpecifier());
mService.requestNetwork(networkCapabilities, null, 0, null,
ConnectivityManager.TYPE_WIFI);
- fail("ConnectivityService requestNetwork with MatchAllNetworkSpecifier");
- } catch (IllegalArgumentException expected) {
- // expected
- }
+ });
class NonParcelableSpecifier extends NetworkSpecifier {
public boolean satisfiedBy(NetworkSpecifier other) { return false; }
@@ -3003,24 +2674,22 @@
@Override public int describeContents() { return 0; }
@Override public void writeToParcel(Parcel p, int flags) {}
}
- NetworkRequest.Builder builder;
- builder = new NetworkRequest.Builder().addTransportType(TRANSPORT_ETHERNET);
- try {
+ final NetworkRequest.Builder builder =
+ new NetworkRequest.Builder().addTransportType(TRANSPORT_ETHERNET);
+ assertThrows(ClassCastException.class, () -> {
builder.setNetworkSpecifier(new NonParcelableSpecifier());
Parcel parcelW = Parcel.obtain();
builder.build().writeToParcel(parcelW, 0);
- fail("Parceling a non-parcelable specifier did not throw an exception");
- } catch (Exception e) {
- // expected
- }
+ });
- builder = new NetworkRequest.Builder().addTransportType(TRANSPORT_ETHERNET);
- builder.setNetworkSpecifier(new ParcelableSpecifier());
- NetworkRequest nr = builder.build();
+ final NetworkRequest nr =
+ new NetworkRequest.Builder().addTransportType(TRANSPORT_ETHERNET)
+ .setNetworkSpecifier(new ParcelableSpecifier())
+ .build();
assertNotNull(nr);
- try {
+ assertThrows(BadParcelableException.class, () -> {
Parcel parcelW = Parcel.obtain();
nr.writeToParcel(parcelW, 0);
byte[] bytes = parcelW.marshall();
@@ -3030,14 +2699,11 @@
parcelR.unmarshall(bytes, 0, bytes.length);
parcelR.setDataPosition(0);
NetworkRequest rereadNr = NetworkRequest.CREATOR.createFromParcel(parcelR);
- fail("Unparceling a non-framework NetworkSpecifier did not throw an exception");
- } catch (Exception e) {
- // expected
- }
+ });
}
@Test
- public void testNetworkSpecifierUidSpoofSecurityException() {
+ public void testNetworkSpecifierUidSpoofSecurityException() throws Exception {
class UidAwareNetworkSpecifier extends NetworkSpecifier implements Parcelable {
@Override
public boolean satisfiedBy(NetworkSpecifier other) {
@@ -3055,19 +2721,16 @@
public void writeToParcel(Parcel dest, int flags) {}
}
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
UidAwareNetworkSpecifier networkSpecifier = new UidAwareNetworkSpecifier();
NetworkRequest networkRequest = newWifiRequestBuilder().setNetworkSpecifier(
networkSpecifier).build();
TestNetworkCallback networkCallback = new TestNetworkCallback();
- try {
+ assertThrows(SecurityException.class, () -> {
mCm.requestNetwork(networkRequest, networkCallback);
- fail("Network request with spoofed UID did not throw a SecurityException");
- } catch (SecurityException e) {
- // expected
- }
+ });
}
@Test
@@ -3079,36 +2742,20 @@
.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
- }
+ assertThrows(SecurityException.class, () ->
+ mCm.registerNetworkCallback(r, new NetworkCallback()));
- try {
- mCm.registerNetworkCallback(r, PendingIntent.getService(
- mServiceContext, 0, new Intent(), 0));
- fail("Expected SecurityException filing a callback with signal strength");
- } catch (SecurityException expected) {
- // expected
- }
+ assertThrows(SecurityException.class, () ->
+ mCm.registerNetworkCallback(r, PendingIntent.getService(
+ mServiceContext, 0, new Intent(), 0)));
// 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
- }
+ assertThrows(IllegalArgumentException.class, () ->
+ mCm.requestNetwork(r, new NetworkCallback()));
- try {
- mCm.requestNetwork(r, PendingIntent.getService(
- mServiceContext, 0, new Intent(), 0));
- fail("Expected IllegalArgumentException filing a request with signal strength");
- } catch (IllegalArgumentException expected) {
- // expected
- }
+ assertThrows(IllegalArgumentException.class, () ->
+ mCm.requestNetwork(r, PendingIntent.getService(
+ mServiceContext, 0, new Intent(), 0)));
}
@Test
@@ -3127,14 +2774,14 @@
cellNetworkCallback.assertNoCallback();
// Bring up cell and expect CALLBACK_AVAILABLE.
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Bring up wifi and expect CALLBACK_AVAILABLE.
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
cellNetworkCallback.assertNoCallback();
defaultNetworkCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
@@ -3142,12 +2789,12 @@
// Bring down cell. Expect no default network callback, since it wasn't the default.
mCellNetworkAgent.disconnect();
- cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
defaultNetworkCallback.assertNoCallback();
assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Bring up cell. Expect no default network callback, since it won't be the default.
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
defaultNetworkCallback.assertNoCallback();
@@ -3157,16 +2804,17 @@
// followed by AVAILABLE cell.
mWiFiNetworkAgent.disconnect();
cellNetworkCallback.assertNoCallback();
- defaultNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ defaultNetworkCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
defaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
mCellNetworkAgent.disconnect();
- cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
- defaultNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
+ defaultNetworkCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
waitForIdle();
assertEquals(null, mCm.getActiveNetwork());
final int uid = Process.myUid();
- final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+ final TestNetworkAgentWrapper
+ vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
final ArraySet<UidRange> ranges = new ArraySet<>();
ranges.add(new UidRange(uid, uid));
mMockVpn.setNetworkAgent(vpnNetworkAgent);
@@ -3177,7 +2825,7 @@
assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
vpnNetworkAgent.disconnect();
- defaultNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ defaultNetworkCallback.expectCallback(CallbackRecord.LOST, vpnNetworkAgent);
waitForIdle();
assertEquals(null, mCm.getActiveNetwork());
}
@@ -3191,7 +2839,7 @@
mCm.requestNetwork(cellRequest, cellNetworkCallback);
// Bring up the mobile network.
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
// We should get onAvailable(), onCapabilitiesChanged(), and
@@ -3205,14 +2853,15 @@
lp.setInterfaceName("foonet_data0");
mCellNetworkAgent.sendLinkProperties(lp);
// We should get onLinkPropertiesChanged().
- cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED,
+ mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
// Suspend the network.
mCellNetworkAgent.suspend();
cellNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_SUSPENDED,
mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.SUSPENDED, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.SUSPENDED, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
// Register a garden variety default network request.
@@ -3227,7 +2876,7 @@
mCellNetworkAgent.resume();
cellNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_SUSPENDED,
mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.RESUMED, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.RESUMED, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
dfltNetworkCallback = new TestNetworkCallback();
@@ -3260,7 +2909,7 @@
waitForIdle();
}
- private boolean isForegroundNetwork(MockNetworkAgent network) {
+ private boolean isForegroundNetwork(TestNetworkAgentWrapper network) {
NetworkCapabilities nc = mCm.getNetworkCapabilities(network.getNetwork());
assertNotNull(nc);
return nc.hasCapability(NET_CAPABILITY_FOREGROUND);
@@ -3279,21 +2928,21 @@
mCm.registerNetworkCallback(request, callback);
mCm.registerNetworkCallback(fgRequest, fgCallback);
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
fgCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
assertTrue(isForegroundNetwork(mCellNetworkAgent));
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
// When wifi connects, cell lingers.
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
fgCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- fgCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ fgCallback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
fgCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
assertTrue(isForegroundNetwork(mCellNetworkAgent));
assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
@@ -3301,7 +2950,7 @@
// When lingering is complete, cell is still there but is now in the background.
waitForIdle();
int timeoutMs = TEST_LINGER_DELAY_MS + TEST_LINGER_DELAY_MS / 4;
- fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent, timeoutMs);
+ fgCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent, timeoutMs);
// Expect a network capabilities update sans FOREGROUND.
callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
assertFalse(isForegroundNetwork(mCellNetworkAgent));
@@ -3327,7 +2976,7 @@
// Release the request. The network immediately goes into the background, since it was not
// lingering.
mCm.unregisterNetworkCallback(cellCallback);
- fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ fgCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
// Expect a network capabilities update sans FOREGROUND.
callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
assertFalse(isForegroundNetwork(mCellNetworkAgent));
@@ -3335,8 +2984,8 @@
// Disconnect wifi and check that cell is foreground again.
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- fgCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ fgCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
fgCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
assertTrue(isForegroundNetwork(mCellNetworkAgent));
@@ -3372,20 +3021,20 @@
};
}
- assertTimeLimit("Registering callbacks", REGISTER_TIME_LIMIT_MS, () -> {
+ assertRunsInAtMost("Registering callbacks", REGISTER_TIME_LIMIT_MS, () -> {
for (NetworkCallback cb : callbacks) {
mCm.registerNetworkCallback(request, cb);
}
});
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
// Don't request that the network validate, because otherwise connect() will block until
// the network gets NET_CAPABILITY_VALIDATED, after all the callbacks below have fired,
// and we won't actually measure anything.
mCellNetworkAgent.connect(false);
long onAvailableDispatchingDuration = durationOf(() -> {
- awaitLatch(availableLatch, 10 * CONNECT_TIME_LIMIT_MS);
+ await(availableLatch, 10 * CONNECT_TIME_LIMIT_MS);
});
Log.d(TAG, String.format("Dispatched %d of %d onAvailable callbacks in %dms",
NUM_REQUESTS - availableLatch.getCount(), NUM_REQUESTS,
@@ -3395,12 +3044,12 @@
onAvailableDispatchingDuration <= CONNECT_TIME_LIMIT_MS);
// Give wifi a high enough score that we'll linger cell when wifi comes up.
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.adjustScore(40);
mWiFiNetworkAgent.connect(false);
long onLostDispatchingDuration = durationOf(() -> {
- awaitLatch(losingLatch, 10 * SWITCH_TIME_LIMIT_MS);
+ await(losingLatch, 10 * SWITCH_TIME_LIMIT_MS);
});
Log.d(TAG, String.format("Dispatched %d of %d onLosing callbacks in %dms",
NUM_REQUESTS - losingLatch.getCount(), NUM_REQUESTS, onLostDispatchingDuration));
@@ -3408,33 +3057,13 @@
NUM_REQUESTS, onLostDispatchingDuration, SWITCH_TIME_LIMIT_MS),
onLostDispatchingDuration <= SWITCH_TIME_LIMIT_MS);
- assertTimeLimit("Unregistering callbacks", UNREGISTER_TIME_LIMIT_MS, () -> {
+ assertRunsInAtMost("Unregistering callbacks", UNREGISTER_TIME_LIMIT_MS, () -> {
for (NetworkCallback cb : callbacks) {
mCm.unregisterNetworkCallback(cb);
}
});
}
- private long durationOf(Runnable fn) {
- long startTime = SystemClock.elapsedRealtime();
- fn.run();
- return SystemClock.elapsedRealtime() - startTime;
- }
-
- private void assertTimeLimit(String descr, long timeLimit, Runnable fn) {
- long timeTaken = durationOf(fn);
- String msg = String.format("%s: took %dms, limit was %dms", descr, timeTaken, timeLimit);
- Log.d(TAG, msg);
- assertTrue(msg, timeTaken <= timeLimit);
- }
-
- private boolean awaitLatch(CountDownLatch l, long timeoutMs) {
- try {
- return l.await(timeoutMs, TimeUnit.MILLISECONDS);
- } catch (InterruptedException e) {}
- return false;
- }
-
@Test
public void testMobileDataAlwaysOn() throws Exception {
final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
@@ -3458,7 +3087,7 @@
assertTrue(testFactory.getMyStartRequested());
// Bring up wifi. The factory stops looking for a network.
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
// Score 60 - 40 penalty for not validated yet, then 60 when it validates
testFactory.expectAddRequestsWithScores(20, 60);
mWiFiNetworkAgent.connect(true);
@@ -3475,7 +3104,7 @@
// Bring up cell data and check that the factory stops looking.
assertLength(1, mCm.getAllNetworks());
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
testFactory.expectAddRequestsWithScores(10, 50); // Unvalidated, then validated
mCellNetworkAgent.connect(true);
cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
@@ -3493,7 +3122,7 @@
testFactory.waitForNetworkRequests(1);
// ... and cell data to be torn down.
- cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
assertLength(1, mCm.getAllNetworks());
testFactory.unregister();
@@ -3504,48 +3133,46 @@
@Test
public void testAvoidBadWifiSetting() throws Exception {
final ContentResolver cr = mServiceContext.getContentResolver();
- final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker();
final String settingName = Settings.Global.NETWORK_AVOID_BAD_WIFI;
- tracker.configRestrictsAvoidBadWifi = false;
+ mPolicyTracker.mConfigRestrictsAvoidBadWifi = false;
String[] values = new String[] {null, "0", "1"};
for (int i = 0; i < values.length; i++) {
Settings.Global.putInt(cr, settingName, 1);
- tracker.reevaluate();
+ mPolicyTracker.reevaluate();
waitForIdle();
String msg = String.format("config=false, setting=%s", values[i]);
assertTrue(mService.avoidBadWifi());
- assertFalse(msg, tracker.shouldNotifyWifiUnvalidated());
+ assertFalse(msg, mPolicyTracker.shouldNotifyWifiUnvalidated());
}
- tracker.configRestrictsAvoidBadWifi = true;
+ mPolicyTracker.mConfigRestrictsAvoidBadWifi = true;
Settings.Global.putInt(cr, settingName, 0);
- tracker.reevaluate();
+ mPolicyTracker.reevaluate();
waitForIdle();
assertFalse(mService.avoidBadWifi());
- assertFalse(tracker.shouldNotifyWifiUnvalidated());
+ assertFalse(mPolicyTracker.shouldNotifyWifiUnvalidated());
Settings.Global.putInt(cr, settingName, 1);
- tracker.reevaluate();
+ mPolicyTracker.reevaluate();
waitForIdle();
assertTrue(mService.avoidBadWifi());
- assertFalse(tracker.shouldNotifyWifiUnvalidated());
+ assertFalse(mPolicyTracker.shouldNotifyWifiUnvalidated());
Settings.Global.putString(cr, settingName, null);
- tracker.reevaluate();
+ mPolicyTracker.reevaluate();
waitForIdle();
assertFalse(mService.avoidBadWifi());
- assertTrue(tracker.shouldNotifyWifiUnvalidated());
+ assertTrue(mPolicyTracker.shouldNotifyWifiUnvalidated());
}
@Test
public void testAvoidBadWifi() throws Exception {
final ContentResolver cr = mServiceContext.getContentResolver();
- final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker();
// Pretend we're on a carrier that restricts switching away from bad wifi.
- tracker.configRestrictsAvoidBadWifi = true;
+ mPolicyTracker.mConfigRestrictsAvoidBadWifi = true;
// File a request for cell to ensure it doesn't go down.
final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
@@ -3564,17 +3191,17 @@
mCm.registerNetworkCallback(validatedWifiRequest, validatedWifiCallback);
Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 0);
- tracker.reevaluate();
+ mPolicyTracker.reevaluate();
// Bring up validated cell.
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
Network cellNetwork = mCellNetworkAgent.getNetwork();
// Bring up validated wifi.
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
validatedWifiCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
@@ -3584,7 +3211,7 @@
mWiFiNetworkAgent.setNetworkInvalid();
mCm.reportNetworkConnectivity(wifiNetwork, false);
defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- validatedWifiCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ validatedWifiCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
// Because avoid bad wifi is off, we don't switch to cellular.
defaultCallback.assertNoCallback();
@@ -3596,14 +3223,14 @@
// Simulate switching to a carrier that does not restrict avoiding bad wifi, and expect
// that we switch back to cell.
- tracker.configRestrictsAvoidBadWifi = false;
- tracker.reevaluate();
+ mPolicyTracker.mConfigRestrictsAvoidBadWifi = false;
+ mPolicyTracker.reevaluate();
defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
assertEquals(mCm.getActiveNetwork(), cellNetwork);
// Switch back to a restrictive carrier.
- tracker.configRestrictsAvoidBadWifi = true;
- tracker.reevaluate();
+ mPolicyTracker.mConfigRestrictsAvoidBadWifi = true;
+ mPolicyTracker.reevaluate();
defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
assertEquals(mCm.getActiveNetwork(), wifiNetwork);
@@ -3618,7 +3245,7 @@
// Disconnect and reconnect wifi to clear the one-time switch above.
mWiFiNetworkAgent.disconnect();
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
validatedWifiCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
@@ -3628,11 +3255,11 @@
mWiFiNetworkAgent.setNetworkInvalid();
mCm.reportNetworkConnectivity(wifiNetwork, false);
defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- validatedWifiCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ validatedWifiCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
// Simulate the user selecting "switch" and checking the don't ask again checkbox.
Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
- tracker.reevaluate();
+ mPolicyTracker.reevaluate();
// We now switch to cell.
defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
@@ -3645,17 +3272,17 @@
// Simulate the user turning the cellular fallback setting off and then on.
// We switch to wifi and then to cell.
Settings.Global.putString(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, null);
- tracker.reevaluate();
+ mPolicyTracker.reevaluate();
defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
assertEquals(mCm.getActiveNetwork(), wifiNetwork);
Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
- tracker.reevaluate();
+ mPolicyTracker.reevaluate();
defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
assertEquals(mCm.getActiveNetwork(), cellNetwork);
// If cell goes down, we switch to wifi.
mCellNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
validatedWifiCallback.assertNoCallback();
@@ -3667,14 +3294,13 @@
@Test
public void testMeteredMultipathPreferenceSetting() throws Exception {
final ContentResolver cr = mServiceContext.getContentResolver();
- final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker();
final String settingName = Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
for (int config : Arrays.asList(0, 3, 2)) {
for (String setting: Arrays.asList(null, "0", "2", "1")) {
- tracker.configMeteredMultipathPreference = config;
+ mPolicyTracker.mConfigMeteredMultipathPreference = config;
Settings.Global.putString(cr, settingName, setting);
- tracker.reevaluate();
+ mPolicyTracker.reevaluate();
waitForIdle();
final int expected = (setting != null) ? Integer.parseInt(setting) : config;
@@ -3689,13 +3315,13 @@
* time-out period expires.
*/
@Test
- public void testSatisfiedNetworkRequestDoesNotTriggerOnUnavailable() {
+ public void testSatisfiedNetworkRequestDoesNotTriggerOnUnavailable() throws Exception {
NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
NetworkCapabilities.TRANSPORT_WIFI).build();
final TestNetworkCallback networkCallback = new TestNetworkCallback();
mCm.requestNetwork(nr, networkCallback, TEST_REQUEST_TIMEOUT_MS);
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, false, false,
TEST_CALLBACK_TIMEOUT_MS);
@@ -3709,18 +3335,18 @@
* not trigger onUnavailable() once the time-out period expires.
*/
@Test
- public void testSatisfiedThenLostNetworkRequestDoesNotTriggerOnUnavailable() {
+ public void testSatisfiedThenLostNetworkRequestDoesNotTriggerOnUnavailable() throws Exception {
NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
NetworkCapabilities.TRANSPORT_WIFI).build();
final TestNetworkCallback networkCallback = new TestNetworkCallback();
mCm.requestNetwork(nr, networkCallback, TEST_REQUEST_TIMEOUT_MS);
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, false, false,
TEST_CALLBACK_TIMEOUT_MS);
mWiFiNetworkAgent.disconnect();
- networkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
// Validate that UNAVAILABLE is not called
networkCallback.assertNoCallback();
@@ -3732,7 +3358,7 @@
* (somehow) satisfied - the callback isn't called later.
*/
@Test
- public void testTimedoutNetworkRequest() {
+ public void testTimedoutNetworkRequest() throws Exception {
NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
NetworkCapabilities.TRANSPORT_WIFI).build();
final TestNetworkCallback networkCallback = new TestNetworkCallback();
@@ -3740,10 +3366,10 @@
mCm.requestNetwork(nr, networkCallback, timeoutMs);
// pass timeout and validate that UNAVAILABLE is called
- networkCallback.expectCallback(CallbackState.UNAVAILABLE, null);
+ networkCallback.expectCallback(CallbackRecord.UNAVAILABLE, null);
// create a network satisfying request - validate that request not triggered
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
networkCallback.assertNoCallback();
}
@@ -3753,7 +3379,7 @@
* trigger the callback.
*/
@Test
- public void testNoCallbackAfterUnregisteredNetworkRequest() {
+ public void testNoCallbackAfterUnregisteredNetworkRequest() throws Exception {
NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
NetworkCapabilities.TRANSPORT_WIFI).build();
final TestNetworkCallback networkCallback = new TestNetworkCallback();
@@ -3766,16 +3392,25 @@
networkCallback.assertNoCallback();
// create a network satisfying request - validate that request not triggered
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
networkCallback.assertNoCallback();
}
+ @Test
+ public void testUnfulfillableNetworkRequest() throws Exception {
+ runUnfulfillableNetworkRequest(false);
+ }
+
+ @Test
+ public void testUnfulfillableNetworkRequestAfterUnregister() throws Exception {
+ runUnfulfillableNetworkRequest(true);
+ }
+
/**
* Validate the callback flow for a factory releasing a request as unfulfillable.
*/
- @Test
- public void testUnfulfillableNetworkRequest() throws Exception {
+ private void runUnfulfillableNetworkRequest(boolean preUnregister) throws Exception {
NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
NetworkCapabilities.TRANSPORT_WIFI).build();
final TestNetworkCallback networkCallback = new TestNetworkCallback();
@@ -3810,11 +3445,25 @@
}
}
- // Simulate the factory releasing the request as unfulfillable and expect onUnavailable!
testFactory.expectRemoveRequests(1);
- testFactory.triggerUnfulfillable(requests.get(newRequestId));
- networkCallback.expectCallback(CallbackState.UNAVAILABLE, null);
- testFactory.waitForRequests();
+ if (preUnregister) {
+ mCm.unregisterNetworkCallback(networkCallback);
+
+ // Simulate the factory releasing the request as unfulfillable: no-op since
+ // the callback has already been unregistered (but a test that no exceptions are
+ // thrown).
+ testFactory.triggerUnfulfillable(requests.get(newRequestId));
+ } else {
+ // Simulate the factory releasing the request as unfulfillable and expect onUnavailable!
+ testFactory.triggerUnfulfillable(requests.get(newRequestId));
+
+ networkCallback.expectCallback(CallbackRecord.UNAVAILABLE, null);
+ testFactory.waitForRequests();
+
+ // unregister network callback - a no-op (since already freed by the
+ // on-unavailable), but should not fail or throw exceptions.
+ mCm.unregisterNetworkCallback(networkCallback);
+ }
testFactory.unregister();
handlerThread.quit();
@@ -3822,7 +3471,7 @@
private static class TestKeepaliveCallback extends PacketKeepaliveCallback {
- public static enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR };
+ public enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR }
private class CallbackValue {
public CallbackType callbackType;
@@ -3870,25 +3519,19 @@
mCallbacks.add(new CallbackValue(CallbackType.ON_ERROR, error));
}
- private void expectCallback(CallbackValue callbackValue) {
- try {
- assertEquals(
- callbackValue,
- mCallbacks.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
- } catch (InterruptedException e) {
- fail(callbackValue.callbackType + " callback not seen after " + TIMEOUT_MS + " ms");
- }
+ private void expectCallback(CallbackValue callbackValue) throws InterruptedException {
+ assertEquals(callbackValue, mCallbacks.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
}
- public void expectStarted() {
+ public void expectStarted() throws Exception {
expectCallback(new CallbackValue(CallbackType.ON_STARTED));
}
- public void expectStopped() {
+ public void expectStopped() throws Exception {
expectCallback(new CallbackValue(CallbackType.ON_STOPPED));
}
- public void expectError(int error) {
+ public void expectError(int error) throws Exception {
expectCallback(new CallbackValue(CallbackType.ON_ERROR, error));
}
}
@@ -3949,25 +3592,20 @@
mCallbacks.add(new CallbackValue(CallbackType.ON_ERROR, error));
}
- private void expectCallback(CallbackValue callbackValue) {
- try {
- assertEquals(
- callbackValue,
- mCallbacks.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
- } catch (InterruptedException e) {
- fail(callbackValue.callbackType + " callback not seen after " + TIMEOUT_MS + " ms");
- }
+ private void expectCallback(CallbackValue callbackValue) throws InterruptedException {
+ assertEquals(callbackValue, mCallbacks.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
}
- public void expectStarted() {
+ public void expectStarted() throws InterruptedException {
expectCallback(new CallbackValue(CallbackType.ON_STARTED));
}
- public void expectStopped() {
+ public void expectStopped() throws InterruptedException {
expectCallback(new CallbackValue(CallbackType.ON_STOPPED));
}
- public void expectError(int error) {
+ public void expectError(int error) throws InterruptedException {
expectCallback(new CallbackValue(CallbackType.ON_ERROR, error));
}
@@ -3978,13 +3616,13 @@
}
}
- private Network connectKeepaliveNetwork(LinkProperties lp) {
+ private Network connectKeepaliveNetwork(LinkProperties lp) throws Exception {
// Ensure the network is disconnected before we do anything.
if (mWiFiNetworkAgent != null) {
assertNull(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()));
}
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
ConditionVariable cv = waitForConnectivityBroadcasts(1);
mWiFiNetworkAgent.connect(true);
waitFor(cv);
@@ -4048,10 +3686,10 @@
callback.expectError(PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
// Check that a started keepalive can be stopped.
- mWiFiNetworkAgent.setStartKeepaliveError(PacketKeepalive.SUCCESS);
+ mWiFiNetworkAgent.setStartKeepaliveEvent(PacketKeepalive.SUCCESS);
ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
callback.expectStarted();
- mWiFiNetworkAgent.setStopKeepaliveError(PacketKeepalive.SUCCESS);
+ mWiFiNetworkAgent.setStopKeepaliveEvent(PacketKeepalive.SUCCESS);
ka.stop();
callback.expectStopped();
@@ -4069,7 +3707,7 @@
ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
callback.expectStarted();
mWiFiNetworkAgent.disconnect();
- waitFor(mWiFiNetworkAgent.getDisconnectedCV());
+ mWiFiNetworkAgent.expectDisconnected();
callback.expectError(PacketKeepalive.ERROR_INVALID_NETWORK);
// ... and that stopping it after that has no adverse effects.
@@ -4080,7 +3718,7 @@
// Reconnect.
myNet = connectKeepaliveNetwork(lp);
- mWiFiNetworkAgent.setStartKeepaliveError(PacketKeepalive.SUCCESS);
+ mWiFiNetworkAgent.setStartKeepaliveEvent(PacketKeepalive.SUCCESS);
// Check that keepalive slots start from 1 and increment. The first one gets slot 1.
mWiFiNetworkAgent.setExpectedKeepaliveSlot(1);
@@ -4111,13 +3749,9 @@
callback3.expectStopped();
}
- @FunctionalInterface
- private interface ThrowingConsumer<T> {
- void accept(T t) throws Exception;
- }
-
// Helper method to prepare the executor and run test
- private void runTestWithSerialExecutors(ThrowingConsumer<Executor> functor) throws Exception {
+ private void runTestWithSerialExecutors(ExceptionUtils.ThrowingConsumer<Executor> functor)
+ throws Exception {
final ExecutorService executorSingleThread = Executors.newSingleThreadExecutor();
final Executor executorInline = (Runnable r) -> r.run();
functor.accept(executorSingleThread);
@@ -4204,12 +3838,12 @@
}
// Check that a started keepalive can be stopped.
- mWiFiNetworkAgent.setStartKeepaliveError(SocketKeepalive.SUCCESS);
+ mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS);
try (SocketKeepalive ka = mCm.createSocketKeepalive(
myNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
ka.start(validKaInterval);
callback.expectStarted();
- mWiFiNetworkAgent.setStopKeepaliveError(SocketKeepalive.SUCCESS);
+ mWiFiNetworkAgent.setStopKeepaliveEvent(SocketKeepalive.SUCCESS);
ka.stop();
callback.expectStopped();
@@ -4249,7 +3883,7 @@
ka.start(validKaInterval);
callback.expectStarted();
mWiFiNetworkAgent.disconnect();
- waitFor(mWiFiNetworkAgent.getDisconnectedCV());
+ mWiFiNetworkAgent.expectDisconnected();
callback.expectError(SocketKeepalive.ERROR_INVALID_NETWORK);
// ... and that stopping it after that has no adverse effects.
@@ -4262,7 +3896,7 @@
// Reconnect.
myNet = connectKeepaliveNetwork(lp);
- mWiFiNetworkAgent.setStartKeepaliveError(SocketKeepalive.SUCCESS);
+ mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS);
// Check that keepalive slots start from 1 and increment. The first one gets slot 1.
mWiFiNetworkAgent.setExpectedKeepaliveSlot(1);
@@ -4299,7 +3933,7 @@
// assertFalse(isUdpPortInUse(srcPort2));
mWiFiNetworkAgent.disconnect();
- waitFor(mWiFiNetworkAgent.getDisconnectedCV());
+ mWiFiNetworkAgent.expectDisconnected();
mWiFiNetworkAgent = null;
}
@@ -4375,7 +4009,7 @@
testSocketV6.close();
mWiFiNetworkAgent.disconnect();
- waitFor(mWiFiNetworkAgent.getDisconnectedCV());
+ mWiFiNetworkAgent.expectDisconnected();
mWiFiNetworkAgent = null;
}
@@ -4391,8 +4025,8 @@
lp.addLinkAddress(new LinkAddress(myIPv4, 25));
lp.addRoute(new RouteInfo(InetAddress.getByName("192.0.2.254")));
Network myNet = connectKeepaliveNetwork(lp);
- mWiFiNetworkAgent.setStartKeepaliveError(SocketKeepalive.SUCCESS);
- mWiFiNetworkAgent.setStopKeepaliveError(SocketKeepalive.SUCCESS);
+ mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS);
+ mWiFiNetworkAgent.setStopKeepaliveEvent(SocketKeepalive.SUCCESS);
TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(executor);
@@ -4428,14 +4062,14 @@
// assertFalse(isUdpPortInUse(srcPort));
mWiFiNetworkAgent.disconnect();
- waitFor(mWiFiNetworkAgent.getDisconnectedCV());
+ mWiFiNetworkAgent.expectDisconnected();
mWiFiNetworkAgent = null;
}
private static boolean isUdpPortInUse(int port) {
try (DatagramSocket ignored = new DatagramSocket(port)) {
return false;
- } catch (IOException ignored) {
+ } catch (IOException alreadyInUse) {
return true;
}
}
@@ -4447,23 +4081,19 @@
}
private static class TestNetworkPinner extends NetworkPinner {
- public static boolean awaitPin(int timeoutMs) {
+ public static boolean awaitPin(int timeoutMs) throws InterruptedException {
synchronized(sLock) {
if (sNetwork == null) {
- try {
- sLock.wait(timeoutMs);
- } catch (InterruptedException e) {}
+ sLock.wait(timeoutMs);
}
return sNetwork != null;
}
}
- public static boolean awaitUnpin(int timeoutMs) {
+ public static boolean awaitUnpin(int timeoutMs) throws InterruptedException {
synchronized(sLock) {
if (sNetwork != null) {
- try {
- sLock.wait(timeoutMs);
- } catch (InterruptedException e) {}
+ sLock.wait(timeoutMs);
}
return sNetwork == null;
}
@@ -4486,7 +4116,7 @@
}
@Test
- public void testNetworkPinner() {
+ public void testNetworkPinner() throws Exception {
NetworkRequest wifiRequest = new NetworkRequest.Builder()
.addTransportType(TRANSPORT_WIFI)
.build();
@@ -4495,9 +4125,9 @@
TestNetworkPinner.pin(mServiceContext, wifiRequest);
assertNull(mCm.getBoundNetworkForProcess());
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
// When wi-fi connects, expect to be pinned.
@@ -4510,7 +4140,7 @@
assertNotPinnedToWifi();
// Reconnecting does not cause the pin to come back.
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
assertFalse(TestNetworkPinner.awaitPin(100));
assertNotPinnedToWifi();
@@ -4532,14 +4162,14 @@
// Pinning takes effect even if the pinned network is the default when the pin is set...
TestNetworkPinner.pin(mServiceContext, wifiRequest);
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
assertTrue(TestNetworkPinner.awaitPin(100));
assertPinnedToWifiWithWifiDefault();
// ... and is maintained even when that network is no longer the default.
cv = waitForConnectivityBroadcasts(1);
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mCellNetworkAgent.connect(true);
waitFor(cv);
assertPinnedToWifiWithCellDefault();
@@ -4581,25 +4211,20 @@
}
// Test that the limit is enforced when MAX_REQUESTS simultaneous requests are added.
- try {
- mCm.requestNetwork(networkRequest, new NetworkCallback());
- fail("Registering " + MAX_REQUESTS + " network requests did not throw exception");
- } catch (TooManyRequestsException expected) {}
- try {
- mCm.registerNetworkCallback(networkRequest, new NetworkCallback());
- fail("Registering " + MAX_REQUESTS + " network callbacks did not throw exception");
- } catch (TooManyRequestsException expected) {}
- try {
- mCm.requestNetwork(networkRequest,
- PendingIntent.getBroadcast(mContext, 0, new Intent("c"), 0));
- fail("Registering " + MAX_REQUESTS + " PendingIntent requests did not throw exception");
- } catch (TooManyRequestsException expected) {}
- try {
- mCm.registerNetworkCallback(networkRequest,
- PendingIntent.getBroadcast(mContext, 0, new Intent("d"), 0));
- fail("Registering " + MAX_REQUESTS
- + " PendingIntent callbacks did not throw exception");
- } catch (TooManyRequestsException expected) {}
+ assertThrows(TooManyRequestsException.class, () ->
+ mCm.requestNetwork(networkRequest, new NetworkCallback())
+ );
+ assertThrows(TooManyRequestsException.class, () ->
+ mCm.registerNetworkCallback(networkRequest, new NetworkCallback())
+ );
+ assertThrows(TooManyRequestsException.class, () ->
+ mCm.requestNetwork(networkRequest,
+ PendingIntent.getBroadcast(mContext, 0, new Intent("c"), 0))
+ );
+ assertThrows(TooManyRequestsException.class, () ->
+ mCm.registerNetworkCallback(networkRequest,
+ PendingIntent.getBroadcast(mContext, 0, new Intent("d"), 0))
+ );
for (Object o : registered) {
if (o instanceof NetworkCallback) {
@@ -4643,11 +4268,11 @@
}
@Test
- public void testNetworkInfoOfTypeNone() {
+ public void testNetworkInfoOfTypeNone() throws Exception {
ConditionVariable broadcastCV = waitForConnectivityBroadcasts(1);
verifyNoNetwork();
- MockNetworkAgent wifiAware = new MockNetworkAgent(TRANSPORT_WIFI_AWARE);
+ TestNetworkAgentWrapper wifiAware = new TestNetworkAgentWrapper(TRANSPORT_WIFI_AWARE);
assertNull(mCm.getActiveNetworkInfo());
Network[] allNetworks = mCm.getAllNetworks();
@@ -4673,7 +4298,7 @@
// Disconnect wifi aware network.
wifiAware.disconnect();
- callback.expectCallbackLike((info) -> info.state == CallbackState.LOST, TIMEOUT_MS);
+ callback.expectCallbackThat(TIMEOUT_MS, (info) -> info instanceof CallbackRecord.Lost);
mCm.unregisterNetworkCallback(callback);
verifyNoNetwork();
@@ -4690,21 +4315,21 @@
assertNull(mCm.getLinkProperties(TYPE_NONE));
assertFalse(mCm.isNetworkSupported(TYPE_NONE));
- assertException(() -> { mCm.networkCapabilitiesForType(TYPE_NONE); },
- IllegalArgumentException.class);
+ assertThrows(IllegalArgumentException.class,
+ () -> { mCm.networkCapabilitiesForType(TYPE_NONE); });
Class<UnsupportedOperationException> unsupported = UnsupportedOperationException.class;
- assertException(() -> { mCm.startUsingNetworkFeature(TYPE_WIFI, ""); }, unsupported);
- assertException(() -> { mCm.stopUsingNetworkFeature(TYPE_WIFI, ""); }, unsupported);
+ assertThrows(unsupported, () -> { mCm.startUsingNetworkFeature(TYPE_WIFI, ""); });
+ assertThrows(unsupported, () -> { mCm.stopUsingNetworkFeature(TYPE_WIFI, ""); });
// TODO: let test context have configuration application target sdk version
// and test that pre-M requesting for TYPE_NONE sends back APN_REQUEST_FAILED
- assertException(() -> { mCm.startUsingNetworkFeature(TYPE_NONE, ""); }, unsupported);
- assertException(() -> { mCm.stopUsingNetworkFeature(TYPE_NONE, ""); }, unsupported);
- assertException(() -> { mCm.requestRouteToHostAddress(TYPE_NONE, null); }, unsupported);
+ assertThrows(unsupported, () -> { mCm.startUsingNetworkFeature(TYPE_NONE, ""); });
+ assertThrows(unsupported, () -> { mCm.stopUsingNetworkFeature(TYPE_NONE, ""); });
+ assertThrows(unsupported, () -> { mCm.requestRouteToHostAddress(TYPE_NONE, null); });
}
@Test
- public void testLinkPropertiesEnsuresDirectlyConnectedRoutes() {
+ public void testLinkPropertiesEnsuresDirectlyConnectedRoutes() throws Exception {
final NetworkRequest networkRequest = new NetworkRequest.Builder()
.addTransportType(TRANSPORT_WIFI).build();
final TestNetworkCallback networkCallback = new TestNetworkCallback();
@@ -4720,16 +4345,17 @@
// Verify direct routes are added when network agent is first registered in
// ConnectivityService.
- MockNetworkAgent networkAgent = new MockNetworkAgent(TRANSPORT_WIFI, lp);
+ TestNetworkAgentWrapper networkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, lp);
networkAgent.connect(true);
- networkCallback.expectCallback(CallbackState.AVAILABLE, networkAgent);
- networkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, networkAgent);
- CallbackInfo cbi = networkCallback.expectCallback(CallbackState.LINK_PROPERTIES,
+ networkCallback.expectCallback(CallbackRecord.AVAILABLE, networkAgent);
+ networkCallback.expectCallback(CallbackRecord.NETWORK_CAPS_UPDATED, networkAgent);
+ CallbackRecord.LinkPropertiesChanged cbi =
+ networkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED,
networkAgent);
- networkCallback.expectCallback(CallbackState.BLOCKED_STATUS, networkAgent);
+ networkCallback.expectCallback(CallbackRecord.BLOCKED_STATUS, networkAgent);
networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, networkAgent);
networkCallback.assertNoCallback();
- checkDirectlyConnectedRoutes(cbi.arg, Arrays.asList(myIpv4Address),
+ checkDirectlyConnectedRoutes(cbi.getLp(), Arrays.asList(myIpv4Address),
Arrays.asList(myIpv4DefaultRoute));
checkDirectlyConnectedRoutes(mCm.getLinkProperties(networkAgent.getNetwork()),
Arrays.asList(myIpv4Address), Arrays.asList(myIpv4DefaultRoute));
@@ -4741,9 +4367,9 @@
newLp.addLinkAddress(myIpv6Address1);
newLp.addLinkAddress(myIpv6Address2);
networkAgent.sendLinkProperties(newLp);
- cbi = networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, networkAgent);
+ cbi = networkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED, networkAgent);
networkCallback.assertNoCallback();
- checkDirectlyConnectedRoutes(cbi.arg,
+ checkDirectlyConnectedRoutes(cbi.getLp(),
Arrays.asList(myIpv4Address, myIpv6Address1, myIpv6Address2),
Arrays.asList(myIpv4DefaultRoute));
mCm.unregisterNetworkCallback(networkCallback);
@@ -4751,8 +4377,8 @@
@Test
public void testStatsIfacesChanged() throws Exception {
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
Network[] onlyCell = new Network[] {mCellNetworkAgent.getNetwork()};
Network[] onlyWifi = new Network[] {mWiFiNetworkAgent.getNetwork()};
@@ -4767,11 +4393,8 @@
mCellNetworkAgent.sendLinkProperties(cellLp);
waitForIdle();
verify(mStatsService, atLeastOnce())
- .forceUpdateIfaces(
- eq(onlyCell),
- eq(new VpnInfo[0]),
- any(NetworkState[].class),
- eq(MOBILE_IFNAME));
+ .forceUpdateIfaces(eq(onlyCell), any(NetworkState[].class), eq(MOBILE_IFNAME),
+ eq(new VpnInfo[0]));
reset(mStatsService);
// Default network switch should update ifaces.
@@ -4780,65 +4403,47 @@
waitForIdle();
assertEquals(wifiLp, mService.getActiveLinkProperties());
verify(mStatsService, atLeastOnce())
- .forceUpdateIfaces(
- eq(onlyWifi),
- eq(new VpnInfo[0]),
- any(NetworkState[].class),
- eq(WIFI_IFNAME));
+ .forceUpdateIfaces(eq(onlyWifi), any(NetworkState[].class), eq(WIFI_IFNAME),
+ eq(new VpnInfo[0]));
reset(mStatsService);
// Disconnect should update ifaces.
mWiFiNetworkAgent.disconnect();
waitForIdle();
verify(mStatsService, atLeastOnce())
- .forceUpdateIfaces(
- eq(onlyCell),
- eq(new VpnInfo[0]),
- any(NetworkState[].class),
- eq(MOBILE_IFNAME));
+ .forceUpdateIfaces(eq(onlyCell), any(NetworkState[].class),
+ eq(MOBILE_IFNAME), eq(new VpnInfo[0]));
reset(mStatsService);
// Metered change should update ifaces
mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
waitForIdle();
verify(mStatsService, atLeastOnce())
- .forceUpdateIfaces(
- eq(onlyCell),
- eq(new VpnInfo[0]),
- any(NetworkState[].class),
- eq(MOBILE_IFNAME));
+ .forceUpdateIfaces(eq(onlyCell), any(NetworkState[].class), eq(MOBILE_IFNAME),
+ eq(new VpnInfo[0]));
reset(mStatsService);
mCellNetworkAgent.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
waitForIdle();
verify(mStatsService, atLeastOnce())
- .forceUpdateIfaces(
- eq(onlyCell),
- eq(new VpnInfo[0]),
- any(NetworkState[].class),
- eq(MOBILE_IFNAME));
+ .forceUpdateIfaces(eq(onlyCell), any(NetworkState[].class), eq(MOBILE_IFNAME),
+ eq(new VpnInfo[0]));
reset(mStatsService);
// Captive portal change shouldn't update ifaces
mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL);
waitForIdle();
verify(mStatsService, never())
- .forceUpdateIfaces(
- eq(onlyCell),
- eq(new VpnInfo[0]),
- any(NetworkState[].class),
- eq(MOBILE_IFNAME));
+ .forceUpdateIfaces(eq(onlyCell), any(NetworkState[].class), eq(MOBILE_IFNAME),
+ eq(new VpnInfo[0]));
reset(mStatsService);
// Roaming change should update ifaces
mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
waitForIdle();
verify(mStatsService, atLeastOnce())
- .forceUpdateIfaces(
- eq(onlyCell),
- eq(new VpnInfo[0]),
- any(NetworkState[].class),
- eq(MOBILE_IFNAME));
+ .forceUpdateIfaces(eq(onlyCell), any(NetworkState[].class), eq(MOBILE_IFNAME),
+ eq(new VpnInfo[0]));
reset(mStatsService);
}
@@ -4849,7 +4454,7 @@
// Clear any interactions that occur as a result of CS starting up.
reset(mMockDnsResolver);
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
waitForIdle();
verify(mMockDnsResolver, never()).setResolverConfiguration(any());
verifyNoMoreInteractions(mMockDnsResolver);
@@ -4868,7 +4473,10 @@
mCellNetworkAgent.sendLinkProperties(cellLp);
mCellNetworkAgent.connect(false);
waitForIdle();
- // CS tells netd about the empty DNS config for this network.
+
+ verify(mMockDnsResolver, times(1)).createNetworkCache(
+ eq(mCellNetworkAgent.getNetwork().netId));
+ // CS tells dnsresolver about the empty DNS config for this network.
verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(any());
reset(mMockDnsResolver);
@@ -4929,7 +4537,7 @@
.addTransportType(TRANSPORT_CELLULAR).build();
mCm.requestNetwork(cellRequest, cellNetworkCallback);
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
waitForIdle();
// CS tells netd about the empty DNS config for this network.
verify(mMockDnsResolver, never()).setResolverConfiguration(any());
@@ -4952,26 +4560,28 @@
mCellNetworkAgent.sendLinkProperties(cellLp);
mCellNetworkAgent.connect(false);
waitForIdle();
+ verify(mMockDnsResolver, times(1)).createNetworkCache(
+ eq(mCellNetworkAgent.getNetwork().netId));
verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
mResolverParamsParcelCaptor.capture());
ResolverParamsParcel resolvrParams = mResolverParamsParcelCaptor.getValue();
assertEquals(2, resolvrParams.tlsServers.length);
assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers,
- new String[]{"2001:db8::1", "192.0.2.1"}));
+ new String[] { "2001:db8::1", "192.0.2.1" }));
// Opportunistic mode.
assertEquals(2, resolvrParams.tlsServers.length);
assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers,
- new String[]{"2001:db8::1", "192.0.2.1"}));
+ new String[] { "2001:db8::1", "192.0.2.1" }));
reset(mMockDnsResolver);
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES,
+ cellNetworkCallback.expectCallback(CallbackRecord.AVAILABLE, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.NETWORK_CAPS_UPDATED,
mCellNetworkAgent);
- CallbackInfo cbi = cellNetworkCallback.expectCallback(
- CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.BLOCKED_STATUS, mCellNetworkAgent);
+ CallbackRecord.LinkPropertiesChanged cbi = cellNetworkCallback.expectCallback(
+ CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.BLOCKED_STATUS, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
- assertFalse(((LinkProperties)cbi.arg).isPrivateDnsActive());
- assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
+ assertFalse(cbi.getLp().isPrivateDnsActive());
+ assertNull(cbi.getLp().getPrivateDnsServerName());
setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com");
verify(mMockDnsResolver, times(1)).setResolverConfiguration(
@@ -4979,7 +4589,7 @@
resolvrParams = mResolverParamsParcelCaptor.getValue();
assertEquals(2, resolvrParams.servers.length);
assertTrue(ArrayUtils.containsAll(resolvrParams.servers,
- new String[]{"2001:db8::1", "192.0.2.1"}));
+ new String[] { "2001:db8::1", "192.0.2.1" }));
reset(mMockDnsResolver);
cellNetworkCallback.assertNoCallback();
@@ -4989,21 +4599,21 @@
resolvrParams = mResolverParamsParcelCaptor.getValue();
assertEquals(2, resolvrParams.servers.length);
assertTrue(ArrayUtils.containsAll(resolvrParams.servers,
- new String[]{"2001:db8::1", "192.0.2.1"}));
+ new String[] { "2001:db8::1", "192.0.2.1" }));
assertEquals(2, resolvrParams.tlsServers.length);
assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers,
- new String[]{"2001:db8::1", "192.0.2.1"}));
+ new String[] { "2001:db8::1", "192.0.2.1" }));
reset(mMockDnsResolver);
cellNetworkCallback.assertNoCallback();
setPrivateDnsSettings(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, "strict.example.com");
// Can't test dns configuration for strict mode without properly mocking
// out the DNS lookups, but can test that LinkProperties is updated.
- cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES,
+ cbi = cellNetworkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED,
mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
- assertTrue(((LinkProperties)cbi.arg).isPrivateDnsActive());
- assertEquals("strict.example.com", ((LinkProperties)cbi.arg).getPrivateDnsServerName());
+ assertTrue(cbi.getLp().isPrivateDnsActive());
+ assertEquals("strict.example.com", cbi.getLp().getPrivateDnsServerName());
}
@Test
@@ -5016,23 +4626,23 @@
.addTransportType(TRANSPORT_CELLULAR).build();
mCm.requestNetwork(cellRequest, cellNetworkCallback);
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
waitForIdle();
LinkProperties lp = new LinkProperties();
mCellNetworkAgent.sendLinkProperties(lp);
mCellNetworkAgent.connect(false);
waitForIdle();
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES,
+ cellNetworkCallback.expectCallback(CallbackRecord.AVAILABLE, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.NETWORK_CAPS_UPDATED,
mCellNetworkAgent);
- CallbackInfo cbi = cellNetworkCallback.expectCallback(
- CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.BLOCKED_STATUS, mCellNetworkAgent);
+ CallbackRecord.LinkPropertiesChanged cbi = cellNetworkCallback.expectCallback(
+ CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.BLOCKED_STATUS, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
- assertFalse(((LinkProperties)cbi.arg).isPrivateDnsActive());
- assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
+ assertFalse(cbi.getLp().isPrivateDnsActive());
+ assertNull(cbi.getLp().getPrivateDnsServerName());
Set<InetAddress> dnsServers = new HashSet<>();
- checkDnsServers(cbi.arg, dnsServers);
+ checkDnsServers(cbi.getLp(), dnsServers);
// Send a validation event for a server that is not part of the current
// resolver config. The validation event should be ignored.
@@ -5044,13 +4654,13 @@
LinkProperties lp2 = new LinkProperties(lp);
lp2.addDnsServer(InetAddress.getByName("145.100.185.16"));
mCellNetworkAgent.sendLinkProperties(lp2);
- cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES,
+ cbi = cellNetworkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED,
mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
- assertFalse(((LinkProperties)cbi.arg).isPrivateDnsActive());
- assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
+ assertFalse(cbi.getLp().isPrivateDnsActive());
+ assertNull(cbi.getLp().getPrivateDnsServerName());
dnsServers.add(InetAddress.getByName("145.100.185.16"));
- checkDnsServers(cbi.arg, dnsServers);
+ checkDnsServers(cbi.getLp(), dnsServers);
// Send a validation event containing a hostname that is not part of
// the current resolver config. The validation event should be ignored.
@@ -5068,39 +4678,39 @@
// private dns fields should be sent.
mService.mNetdEventCallback.onPrivateDnsValidationEvent(
mCellNetworkAgent.getNetwork().netId, "145.100.185.16", "", true);
- cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES,
+ cbi = cellNetworkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED,
mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
- assertTrue(((LinkProperties)cbi.arg).isPrivateDnsActive());
- assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
- checkDnsServers(cbi.arg, dnsServers);
+ assertTrue(cbi.getLp().isPrivateDnsActive());
+ assertNull(cbi.getLp().getPrivateDnsServerName());
+ checkDnsServers(cbi.getLp(), dnsServers);
// The private dns fields in LinkProperties should be preserved when
// the network agent sends unrelated changes.
LinkProperties lp3 = new LinkProperties(lp2);
lp3.setMtu(1300);
mCellNetworkAgent.sendLinkProperties(lp3);
- cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES,
+ cbi = cellNetworkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED,
mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
- assertTrue(((LinkProperties)cbi.arg).isPrivateDnsActive());
- assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
- checkDnsServers(cbi.arg, dnsServers);
- assertEquals(1300, ((LinkProperties)cbi.arg).getMtu());
+ assertTrue(cbi.getLp().isPrivateDnsActive());
+ assertNull(cbi.getLp().getPrivateDnsServerName());
+ checkDnsServers(cbi.getLp(), dnsServers);
+ assertEquals(1300, cbi.getLp().getMtu());
// Removing the only validated server should affect the private dns
// fields in LinkProperties.
LinkProperties lp4 = new LinkProperties(lp3);
lp4.removeDnsServer(InetAddress.getByName("145.100.185.16"));
mCellNetworkAgent.sendLinkProperties(lp4);
- cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES,
+ cbi = cellNetworkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED,
mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
- assertFalse(((LinkProperties)cbi.arg).isPrivateDnsActive());
- assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
+ assertFalse(cbi.getLp().isPrivateDnsActive());
+ assertNull(cbi.getLp().getPrivateDnsServerName());
dnsServers.remove(InetAddress.getByName("145.100.185.16"));
- checkDnsServers(cbi.arg, dnsServers);
- assertEquals(1300, ((LinkProperties)cbi.arg).getMtu());
+ checkDnsServers(cbi.getLp(), dnsServers);
+ assertEquals(1300, cbi.getLp().getMtu());
}
private void checkDirectlyConnectedRoutes(Object callbackObj,
@@ -5127,31 +4737,8 @@
assertTrue(lp.getDnsServers().containsAll(dnsServers));
}
- private static <T> void assertEmpty(T[] ts) {
- int length = ts.length;
- assertEquals("expected empty array, but length was " + length, 0, length);
- }
-
- private static <T> void assertLength(int expected, T[] got) {
- int length = got.length;
- assertEquals(String.format("expected array of length %s, but length was %s for %s",
- expected, length, Arrays.toString(got)), expected, length);
- }
-
- private static <T> void assertException(Runnable block, Class<T> expected) {
- try {
- block.run();
- fail("Expected exception of type " + expected);
- } catch (Exception got) {
- if (!got.getClass().equals(expected)) {
- fail("Expected exception of type " + expected + " but got " + got);
- }
- return;
- }
- }
-
@Test
- public void testVpnNetworkActive() {
+ public void testVpnNetworkActive() throws Exception {
final int uid = Process.myUid();
final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback();
@@ -5174,7 +4761,7 @@
mCm.registerDefaultNetworkCallback(defaultCallback);
defaultCallback.assertNoCallback();
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -5184,14 +4771,16 @@
vpnNetworkCallback.assertNoCallback();
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+ final TestNetworkAgentWrapper
+ vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
final ArraySet<UidRange> ranges = new ArraySet<>();
ranges.add(new UidRange(uid, uid));
mMockVpn.setNetworkAgent(vpnNetworkAgent);
mMockVpn.setUids(ranges);
// VPN networks do not satisfy the default request and are automatically validated
// by NetworkMonitor
- assertFalse(NetworkMonitorUtils.isValidationRequired(vpnNetworkAgent.mNetworkCapabilities));
+ assertFalse(NetworkMonitorUtils.isValidationRequired(
+ vpnNetworkAgent.getNetworkCapabilities()));
vpnNetworkAgent.setNetworkValid();
vpnNetworkAgent.connect(false);
@@ -5205,19 +4794,19 @@
defaultCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- genericNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
+ genericNetworkCallback.expectCallback(CallbackRecord.NETWORK_CAPS_UPDATED, vpnNetworkAgent);
genericNotVpnNetworkCallback.assertNoCallback();
- vpnNetworkCallback.expectCapabilitiesLike(nc -> null == nc.getUids(), vpnNetworkAgent);
- defaultCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent, nc -> null == nc.getUids());
+ defaultCallback.expectCallback(CallbackRecord.NETWORK_CAPS_UPDATED, vpnNetworkAgent);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
ranges.clear();
vpnNetworkAgent.setUids(ranges);
- genericNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ genericNetworkCallback.expectCallback(CallbackRecord.LOST, vpnNetworkAgent);
genericNotVpnNetworkCallback.assertNoCallback();
wifiNetworkCallback.assertNoCallback();
- vpnNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ vpnNetworkCallback.expectCallback(CallbackRecord.LOST, vpnNetworkAgent);
// TODO : The default network callback should actually get a LOST call here (also see the
// comment below for AVAILABLE). This is because ConnectivityService does not look at UID
@@ -5225,7 +4814,7 @@
// can't currently update their UIDs without disconnecting, so this does not matter too
// much, but that is the reason the test here has to check for an update to the
// capabilities instead of the expected LOST then AVAILABLE.
- defaultCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.NETWORK_CAPS_UPDATED, vpnNetworkAgent);
ranges.add(new UidRange(uid, uid));
mMockVpn.setUids(ranges);
@@ -5237,23 +4826,23 @@
vpnNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent);
// TODO : Here like above, AVAILABLE would be correct, but because this can't actually
// happen outside of the test, ConnectivityService does not rematch callbacks.
- defaultCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.NETWORK_CAPS_UPDATED, vpnNetworkAgent);
mWiFiNetworkAgent.disconnect();
- genericNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- genericNotVpnNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- wifiNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ genericNetworkCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ genericNotVpnNetworkCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ wifiNetworkCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
vpnNetworkCallback.assertNoCallback();
defaultCallback.assertNoCallback();
vpnNetworkAgent.disconnect();
- genericNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ genericNetworkCallback.expectCallback(CallbackRecord.LOST, vpnNetworkAgent);
genericNotVpnNetworkCallback.assertNoCallback();
wifiNetworkCallback.assertNoCallback();
- vpnNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
- defaultCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ vpnNetworkCallback.expectCallback(CallbackRecord.LOST, vpnNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, vpnNetworkAgent);
assertEquals(null, mCm.getActiveNetwork());
mCm.unregisterNetworkCallback(genericNetworkCallback);
@@ -5263,19 +4852,20 @@
}
@Test
- public void testVpnWithoutInternet() {
+ public void testVpnWithoutInternet() throws Exception {
final int uid = Process.myUid();
final TestNetworkCallback defaultCallback = new TestNetworkCallback();
mCm.registerDefaultNetworkCallback(defaultCallback);
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+ TestNetworkAgentWrapper
+ vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
final ArraySet<UidRange> ranges = new ArraySet<>();
ranges.add(new UidRange(uid, uid));
mMockVpn.setNetworkAgent(vpnNetworkAgent);
@@ -5293,19 +4883,20 @@
}
@Test
- public void testVpnWithInternet() {
+ public void testVpnWithInternet() throws Exception {
final int uid = Process.myUid();
final TestNetworkCallback defaultCallback = new TestNetworkCallback();
mCm.registerDefaultNetworkCallback(defaultCallback);
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+ TestNetworkAgentWrapper
+ vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
final ArraySet<UidRange> ranges = new ArraySet<>();
ranges.add(new UidRange(uid, uid));
mMockVpn.setNetworkAgent(vpnNetworkAgent);
@@ -5317,14 +4908,68 @@
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
vpnNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, vpnNetworkAgent);
defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
mCm.unregisterNetworkCallback(defaultCallback);
}
@Test
- public void testVpnSetUnderlyingNetworks() {
+ public void testVpnUnvalidated() throws Exception {
+ final TestNetworkCallback callback = new TestNetworkCallback();
+ mCm.registerDefaultNetworkCallback(callback);
+
+ // Bring up Ethernet.
+ mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
+ mEthernetNetworkAgent.connect(true);
+ callback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent);
+ callback.assertNoCallback();
+
+ // Bring up a VPN that has the INTERNET capability, initially unvalidated.
+ final int uid = Process.myUid();
+ final TestNetworkAgentWrapper
+ vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
+ final ArraySet<UidRange> ranges = new ArraySet<>();
+ ranges.add(new UidRange(uid, uid));
+ mMockVpn.setNetworkAgent(vpnNetworkAgent);
+ mMockVpn.setUids(ranges);
+ vpnNetworkAgent.connect(false /* validated */, true /* hasInternet */);
+ mMockVpn.connect();
+
+ // Even though the VPN is unvalidated, it becomes the default network for our app.
+ callback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
+ // TODO: this looks like a spurious callback.
+ callback.expectCallback(CallbackRecord.NETWORK_CAPS_UPDATED, vpnNetworkAgent);
+ callback.assertNoCallback();
+
+ assertTrue(vpnNetworkAgent.getScore() > mEthernetNetworkAgent.getScore());
+ assertEquals(ConnectivityConstants.VPN_DEFAULT_SCORE, vpnNetworkAgent.getScore());
+ assertEquals(vpnNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+
+ NetworkCapabilities nc = mCm.getNetworkCapabilities(vpnNetworkAgent.getNetwork());
+ assertFalse(nc.hasCapability(NET_CAPABILITY_VALIDATED));
+ assertTrue(nc.hasCapability(NET_CAPABILITY_INTERNET));
+
+ assertFalse(NetworkMonitorUtils.isValidationRequired(
+ vpnNetworkAgent.getNetworkCapabilities()));
+ assertTrue(NetworkMonitorUtils.isPrivateDnsValidationRequired(
+ vpnNetworkAgent.getNetworkCapabilities()));
+
+ // Pretend that the VPN network validates.
+ vpnNetworkAgent.setNetworkValid();
+ vpnNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
+ // Expect to see the validated capability, but no other changes, because the VPN is already
+ // the default network for the app.
+ callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, vpnNetworkAgent);
+ callback.assertNoCallback();
+
+ vpnNetworkAgent.disconnect();
+ callback.expectCallback(CallbackRecord.LOST, vpnNetworkAgent);
+ callback.expectAvailableCallbacksValidated(mEthernetNetworkAgent);
+ }
+
+ @Test
+ public void testVpnSetUnderlyingNetworks() throws Exception {
final int uid = Process.myUid();
final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback();
@@ -5336,7 +4981,8 @@
mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
vpnNetworkCallback.assertNoCallback();
- final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+ final TestNetworkAgentWrapper
+ vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
final ArraySet<UidRange> ranges = new ArraySet<>();
ranges.add(new UidRange(uid, uid));
mMockVpn.setNetworkAgent(vpnNetworkAgent);
@@ -5353,76 +4999,76 @@
assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED));
// Connect cell and use it as an underlying network.
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
mService.setUnderlyingNetworksForVpn(
new Network[] { mCellNetworkAgent.getNetwork() });
- vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ (caps) -> caps.hasTransport(TRANSPORT_VPN)
&& caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
- vpnNetworkAgent);
+ && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
mWiFiNetworkAgent.connect(true);
mService.setUnderlyingNetworksForVpn(
new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
- vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ (caps) -> caps.hasTransport(TRANSPORT_VPN)
&& caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
- vpnNetworkAgent);
+ && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
// Don't disconnect, but note the VPN is not using wifi any more.
mService.setUnderlyingNetworksForVpn(
new Network[] { mCellNetworkAgent.getNetwork() });
- vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ (caps) -> caps.hasTransport(TRANSPORT_VPN)
&& caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
- vpnNetworkAgent);
+ && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
// Use Wifi but not cell. Note the VPN is now unmetered.
mService.setUnderlyingNetworksForVpn(
new Network[] { mWiFiNetworkAgent.getNetwork() });
- vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ (caps) -> caps.hasTransport(TRANSPORT_VPN)
&& !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && caps.hasCapability(NET_CAPABILITY_NOT_METERED),
- vpnNetworkAgent);
+ && caps.hasCapability(NET_CAPABILITY_NOT_METERED));
// Use both again.
mService.setUnderlyingNetworksForVpn(
new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
- vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ (caps) -> caps.hasTransport(TRANSPORT_VPN)
&& caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
- vpnNetworkAgent);
+ && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
// Disconnect cell. Receive update without even removing the dead network from the
// underlying networks – it's dead anyway. Not metered any more.
mCellNetworkAgent.disconnect();
- vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ (caps) -> caps.hasTransport(TRANSPORT_VPN)
&& !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && caps.hasCapability(NET_CAPABILITY_NOT_METERED),
- vpnNetworkAgent);
+ && caps.hasCapability(NET_CAPABILITY_NOT_METERED));
// Disconnect wifi too. No underlying networks means this is now metered.
mWiFiNetworkAgent.disconnect();
- vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ (caps) -> caps.hasTransport(TRANSPORT_VPN)
&& !caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
- vpnNetworkAgent);
+ && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
mMockVpn.disconnect();
}
@Test
- public void testNullUnderlyingNetworks() {
+ public void testNullUnderlyingNetworks() throws Exception {
final int uid = Process.myUid();
final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback();
@@ -5434,7 +5080,8 @@
mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
vpnNetworkCallback.assertNoCallback();
- final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+ final TestNetworkAgentWrapper
+ vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
final ArraySet<UidRange> ranges = new ArraySet<>();
ranges.add(new UidRange(uid, uid));
mMockVpn.setNetworkAgent(vpnNetworkAgent);
@@ -5452,23 +5099,23 @@
assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED));
// Connect to Cell; Cell is the default network.
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ (caps) -> caps.hasTransport(TRANSPORT_VPN)
&& caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
- vpnNetworkAgent);
+ && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
// Connect to WiFi; WiFi is the new default.
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
mWiFiNetworkAgent.connect(true);
- vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ (caps) -> caps.hasTransport(TRANSPORT_VPN)
&& !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && caps.hasCapability(NET_CAPABILITY_NOT_METERED),
- vpnNetworkAgent);
+ && caps.hasCapability(NET_CAPABILITY_NOT_METERED));
// Disconnect Cell. The default network did not change, so there shouldn't be any changes in
// the capabilities.
@@ -5477,19 +5124,19 @@
// Disconnect wifi too. Now we have no default network.
mWiFiNetworkAgent.disconnect();
- vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ (caps) -> caps.hasTransport(TRANSPORT_VPN)
&& !caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
- vpnNetworkAgent);
+ && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
mMockVpn.disconnect();
}
@Test
- public void testIsActiveNetworkMeteredOverWifi() {
+ public void testIsActiveNetworkMeteredOverWifi() throws Exception {
// Returns true by default when no network is available.
assertTrue(mCm.isActiveNetworkMetered());
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
mWiFiNetworkAgent.connect(true);
waitForIdle();
@@ -5498,10 +5145,10 @@
}
@Test
- public void testIsActiveNetworkMeteredOverCell() {
+ public void testIsActiveNetworkMeteredOverCell() throws Exception {
// Returns true by default when no network is available.
assertTrue(mCm.isActiveNetworkMetered());
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
mCellNetworkAgent.connect(true);
waitForIdle();
@@ -5510,17 +5157,18 @@
}
@Test
- public void testIsActiveNetworkMeteredOverVpnTrackingPlatformDefault() {
+ public void testIsActiveNetworkMeteredOverVpnTrackingPlatformDefault() throws Exception {
// Returns true by default when no network is available.
assertTrue(mCm.isActiveNetworkMetered());
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
mCellNetworkAgent.connect(true);
waitForIdle();
assertTrue(mCm.isActiveNetworkMetered());
// Connect VPN network. By default it is using current default network (Cell).
- MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+ TestNetworkAgentWrapper
+ vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
final ArraySet<UidRange> ranges = new ArraySet<>();
final int uid = Process.myUid();
ranges.add(new UidRange(uid, uid));
@@ -5536,7 +5184,7 @@
assertTrue(mCm.isActiveNetworkMetered());
// Connect WiFi.
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
mWiFiNetworkAgent.connect(true);
waitForIdle();
@@ -5564,23 +5212,24 @@
}
@Test
- public void testIsActiveNetworkMeteredOverVpnSpecifyingUnderlyingNetworks() {
+ public void testIsActiveNetworkMeteredOverVpnSpecifyingUnderlyingNetworks() throws Exception {
// Returns true by default when no network is available.
assertTrue(mCm.isActiveNetworkMetered());
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
mCellNetworkAgent.connect(true);
waitForIdle();
assertTrue(mCm.isActiveNetworkMetered());
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
mWiFiNetworkAgent.connect(true);
waitForIdle();
assertFalse(mCm.isActiveNetworkMetered());
// Connect VPN network.
- MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+ TestNetworkAgentWrapper
+ vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
final ArraySet<UidRange> ranges = new ArraySet<>();
final int uid = Process.myUid();
ranges.add(new UidRange(uid, uid));
@@ -5635,17 +5284,18 @@
}
@Test
- public void testIsActiveNetworkMeteredOverAlwaysMeteredVpn() {
+ public void testIsActiveNetworkMeteredOverAlwaysMeteredVpn() throws Exception {
// Returns true by default when no network is available.
assertTrue(mCm.isActiveNetworkMetered());
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
mWiFiNetworkAgent.connect(true);
waitForIdle();
assertFalse(mCm.isActiveNetworkMetered());
// Connect VPN network.
- MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+ TestNetworkAgentWrapper
+ vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
final ArraySet<UidRange> ranges = new ArraySet<>();
final int uid = Process.myUid();
ranges.add(new UidRange(uid, uid));
@@ -5682,28 +5332,28 @@
}
@Test
- public void testNetworkBlockedStatus() {
+ public void testNetworkBlockedStatus() throws Exception {
final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
final NetworkRequest cellRequest = new NetworkRequest.Builder()
.addTransportType(TRANSPORT_CELLULAR)
.build();
mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- mService.setUidRulesChanged(RULE_REJECT_ALL);
+ setUidRulesChanged(RULE_REJECT_ALL);
cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
// ConnectivityService should cache it not to invoke the callback again.
- mService.setUidRulesChanged(RULE_REJECT_METERED);
+ setUidRulesChanged(RULE_REJECT_METERED);
cellNetworkCallback.assertNoCallback();
- mService.setUidRulesChanged(RULE_NONE);
+ setUidRulesChanged(RULE_NONE);
cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
- mService.setUidRulesChanged(RULE_REJECT_METERED);
+ setUidRulesChanged(RULE_REJECT_METERED);
cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
// Restrict the network based on UID rule and NOT_METERED capability change.
@@ -5714,18 +5364,18 @@
cellNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED,
mCellNetworkAgent);
cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
- mService.setUidRulesChanged(RULE_ALLOW_METERED);
+ setUidRulesChanged(RULE_ALLOW_METERED);
cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
- mService.setUidRulesChanged(RULE_NONE);
+ setUidRulesChanged(RULE_NONE);
cellNetworkCallback.assertNoCallback();
// Restrict the network based on BackgroundRestricted.
- mService.setRestrictBackgroundChanged(true);
+ setRestrictBackgroundChanged(true);
cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
- mService.setRestrictBackgroundChanged(true);
+ setRestrictBackgroundChanged(true);
cellNetworkCallback.assertNoCallback();
- mService.setRestrictBackgroundChanged(false);
+ setRestrictBackgroundChanged(false);
cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
@@ -5733,30 +5383,30 @@
}
@Test
- public void testNetworkBlockedStatusBeforeAndAfterConnect() {
+ public void testNetworkBlockedStatusBeforeAndAfterConnect() throws Exception {
final TestNetworkCallback defaultCallback = new TestNetworkCallback();
mCm.registerDefaultNetworkCallback(defaultCallback);
// No Networkcallbacks invoked before any network is active.
- mService.setUidRulesChanged(RULE_REJECT_ALL);
- mService.setUidRulesChanged(RULE_NONE);
- mService.setUidRulesChanged(RULE_REJECT_METERED);
+ setUidRulesChanged(RULE_REJECT_ALL);
+ setUidRulesChanged(RULE_NONE);
+ setUidRulesChanged(RULE_REJECT_METERED);
defaultCallback.assertNoCallback();
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
defaultCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mCellNetworkAgent);
// Allow to use the network after switching to NOT_METERED network.
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
mWiFiNetworkAgent.connect(true);
defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
// Switch to METERED network. Restrict the use of the network.
mWiFiNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
defaultCallback.expectAvailableCallbacksValidatedAndBlocked(mCellNetworkAgent);
// Network becomes NOT_METERED.
@@ -5765,12 +5415,12 @@
defaultCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
// Verify there's no Networkcallbacks invoked after data saver on/off.
- mService.setRestrictBackgroundChanged(true);
- mService.setRestrictBackgroundChanged(false);
+ setRestrictBackgroundChanged(true);
+ setRestrictBackgroundChanged(false);
defaultCallback.assertNoCallback();
mCellNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
defaultCallback.assertNoCallback();
mCm.unregisterNetworkCallback(defaultCallback);
@@ -5802,7 +5452,7 @@
}
@Test
- public void testStackedLinkProperties() throws UnknownHostException, RemoteException {
+ public void testStackedLinkProperties() throws Exception {
final LinkAddress myIpv4 = new LinkAddress("1.2.3.4/24");
final LinkAddress myIpv6 = new LinkAddress("2001:db8:1::1/64");
final String kNat64PrefixString = "2001:db8:64:64:64:64::";
@@ -5816,7 +5466,7 @@
mCm.registerNetworkCallback(networkRequest, networkCallback);
// Prepare ipv6 only link properties.
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
final int cellNetId = mCellNetworkAgent.getNetwork().netId;
final LinkProperties cellLp = new LinkProperties();
cellLp.setInterfaceName(MOBILE_IFNAME);
@@ -5825,12 +5475,17 @@
cellLp.addRoute(new RouteInfo(myIpv6, null, MOBILE_IFNAME));
reset(mNetworkManagementService);
reset(mMockDnsResolver);
+ reset(mMockNetd);
when(mNetworkManagementService.getInterfaceConfig(CLAT_PREFIX + MOBILE_IFNAME))
.thenReturn(getClatInterfaceConfig(myIpv4));
// Connect with ipv6 link properties. Expect prefix discovery to be started.
mCellNetworkAgent.sendLinkProperties(cellLp);
mCellNetworkAgent.connect(true);
+
+ verify(mMockNetd, times(1)).networkCreatePhysical(eq(cellNetId), anyInt());
+ verify(mMockDnsResolver, times(1)).createNetworkCache(eq(cellNetId));
+
networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
@@ -5841,7 +5496,7 @@
// the NAT64 prefix was removed because one was never discovered.
cellLp.addLinkAddress(myIpv4);
mCellNetworkAgent.sendLinkProperties(cellLp);
- networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
verify(mMockDnsResolver, times(1)).stopPrefix64Discovery(cellNetId);
verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(any());
@@ -5854,23 +5509,23 @@
cellLp.removeLinkAddress(myIpv4);
cellLp.removeRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME));
mCellNetworkAgent.sendLinkProperties(cellLp);
- networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
// When NAT64 prefix discovery succeeds, LinkProperties are updated and clatd is started.
- Nat464Xlat clat = mService.getNat464Xlat(mCellNetworkAgent);
+ Nat464Xlat clat = getNat464Xlat(mCellNetworkAgent);
assertNull(mCm.getLinkProperties(mCellNetworkAgent.getNetwork()).getNat64Prefix());
mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */,
kNat64PrefixString, 96);
- LinkProperties lpBeforeClat = (LinkProperties) networkCallback.expectCallback(
- CallbackState.LINK_PROPERTIES, mCellNetworkAgent).arg;
+ LinkProperties lpBeforeClat = networkCallback.expectCallback(
+ CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent).getLp();
assertEquals(0, lpBeforeClat.getStackedLinks().size());
assertEquals(kNat64Prefix, lpBeforeClat.getNat64Prefix());
verify(mMockNetd, times(1)).clatdStart(MOBILE_IFNAME, kNat64Prefix.toString());
// Clat iface comes up. Expect stacked link to be added.
clat.interfaceLinkStateChanged(CLAT_PREFIX + MOBILE_IFNAME, true);
- networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
List<LinkProperties> stackedLps = mCm.getLinkProperties(mCellNetworkAgent.getNetwork())
.getStackedLinks();
assertEquals(makeClatLinkProperties(myIpv4), stackedLps.get(0));
@@ -5878,7 +5533,7 @@
// Change trivial linkproperties and see if stacked link is preserved.
cellLp.addDnsServer(InetAddress.getByName("8.8.8.8"));
mCellNetworkAgent.sendLinkProperties(cellLp);
- networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
List<LinkProperties> stackedLpsAfterChange =
mCm.getLinkProperties(mCellNetworkAgent.getNetwork()).getStackedLinks();
@@ -5896,12 +5551,12 @@
cellLp.addLinkAddress(myIpv4);
cellLp.addRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME));
mCellNetworkAgent.sendLinkProperties(cellLp);
- networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
verify(mMockDnsResolver, times(1)).stopPrefix64Discovery(cellNetId);
// As soon as stop is called, the linkproperties lose the stacked interface.
- networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
LinkProperties actualLpAfterIpv4 = mCm.getLinkProperties(mCellNetworkAgent.getNetwork());
LinkProperties expected = new LinkProperties(cellLp);
expected.setNat64Prefix(kNat64Prefix);
@@ -5920,54 +5575,52 @@
// Stopping prefix discovery causes netd to tell us that the NAT64 prefix is gone.
mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, false /* added */,
kNat64PrefixString, 96);
- networkCallback.expectLinkPropertiesLike((lp) -> lp.getNat64Prefix() == null,
- mCellNetworkAgent);
+ networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
+ (lp) -> lp.getNat64Prefix() == null);
// Remove IPv4 address and expect prefix discovery and clatd to be started again.
cellLp.removeLinkAddress(myIpv4);
cellLp.removeRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME));
cellLp.removeDnsServer(InetAddress.getByName("8.8.8.8"));
mCellNetworkAgent.sendLinkProperties(cellLp);
- networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */,
kNat64PrefixString, 96);
- networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
verify(mMockNetd, times(1)).clatdStart(MOBILE_IFNAME, kNat64Prefix.toString());
// Clat iface comes up. Expect stacked link to be added.
clat.interfaceLinkStateChanged(CLAT_PREFIX + MOBILE_IFNAME, true);
- networkCallback.expectLinkPropertiesLike(
- (lp) -> lp.getStackedLinks().size() == 1 && lp.getNat64Prefix() != null,
- mCellNetworkAgent);
+ networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
+ (lp) -> lp.getStackedLinks().size() == 1 && lp.getNat64Prefix() != null);
// NAT64 prefix is removed. Expect that clat is stopped.
mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, false /* added */,
kNat64PrefixString, 96);
- networkCallback.expectLinkPropertiesLike(
- (lp) -> lp.getStackedLinks().size() == 0 && lp.getNat64Prefix() == null,
- mCellNetworkAgent);
+ networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
+ (lp) -> lp.getStackedLinks().size() == 0 && lp.getNat64Prefix() == null);
verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
- networkCallback.expectLinkPropertiesLike((lp) -> lp.getStackedLinks().size() == 0,
- mCellNetworkAgent);
+ networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
+ (lp) -> lp.getStackedLinks().size() == 0);
// Clean up.
mCellNetworkAgent.disconnect();
- networkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
networkCallback.assertNoCallback();
mCm.unregisterNetworkCallback(networkCallback);
}
@Test
- public void testDataActivityTracking() throws RemoteException {
+ public void testDataActivityTracking() throws Exception {
final TestNetworkCallback networkCallback = new TestNetworkCallback();
final NetworkRequest networkRequest = new NetworkRequest.Builder()
.addCapability(NET_CAPABILITY_INTERNET)
.build();
mCm.registerNetworkCallback(networkRequest, networkCallback);
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
final LinkProperties cellLp = new LinkProperties();
cellLp.setInterfaceName(MOBILE_IFNAME);
mCellNetworkAgent.sendLinkProperties(cellLp);
@@ -5977,7 +5630,7 @@
verify(mNetworkManagementService, times(1)).addIdleTimer(eq(MOBILE_IFNAME), anyInt(),
eq(ConnectivityManager.TYPE_MOBILE));
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
final LinkProperties wifiLp = new LinkProperties();
wifiLp.setInterfaceName(WIFI_IFNAME);
mWiFiNetworkAgent.sendLinkProperties(wifiLp);
@@ -5986,7 +5639,7 @@
reset(mNetworkManagementService);
mWiFiNetworkAgent.connect(true);
networkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- networkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
verify(mNetworkManagementService, times(1)).addIdleTimer(eq(WIFI_IFNAME), anyInt(),
eq(ConnectivityManager.TYPE_WIFI));
@@ -5995,26 +5648,26 @@
// Disconnect wifi and switch back to cell
reset(mNetworkManagementService);
mWiFiNetworkAgent.disconnect();
- networkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
assertNoCallbacks(networkCallback);
verify(mNetworkManagementService, times(1)).removeIdleTimer(eq(WIFI_IFNAME));
verify(mNetworkManagementService, times(1)).addIdleTimer(eq(MOBILE_IFNAME), anyInt(),
eq(ConnectivityManager.TYPE_MOBILE));
// reconnect wifi
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
wifiLp.setInterfaceName(WIFI_IFNAME);
mWiFiNetworkAgent.sendLinkProperties(wifiLp);
mWiFiNetworkAgent.connect(true);
networkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- networkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
// Disconnect cell
reset(mNetworkManagementService);
reset(mMockNetd);
mCellNetworkAgent.disconnect();
- networkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
// LOST callback is triggered earlier than removing idle timer. Broadcast should also be
// sent as network being switched. Ensure rule removal for cell will not be triggered
// unexpectedly before network being removed.
@@ -6022,7 +5675,7 @@
verify(mNetworkManagementService, times(0)).removeIdleTimer(eq(MOBILE_IFNAME));
verify(mMockNetd, times(1)).networkDestroy(eq(mCellNetworkAgent.getNetwork().netId));
verify(mMockDnsResolver, times(1))
- .clearResolverConfiguration(eq(mCellNetworkAgent.getNetwork().netId));
+ .destroyNetworkCache(eq(mCellNetworkAgent.getNetwork().netId));
// Disconnect wifi
ConditionVariable cv = waitForConnectivityBroadcasts(1);
@@ -6035,24 +5688,20 @@
mCm.unregisterNetworkCallback(networkCallback);
}
- private void verifyTcpBufferSizeChange(String tcpBufferSizes) {
+ private void verifyTcpBufferSizeChange(String tcpBufferSizes) throws Exception {
String[] values = tcpBufferSizes.split(",");
String rmemValues = String.join(" ", values[0], values[1], values[2]);
String wmemValues = String.join(" ", values[3], values[4], values[5]);
waitForIdle();
- try {
- verify(mMockNetd, atLeastOnce()).setTcpRWmemorySize(rmemValues, wmemValues);
- } catch (RemoteException e) {
- fail("mMockNetd should never throw RemoteException");
- }
+ verify(mMockNetd, atLeastOnce()).setTcpRWmemorySize(rmemValues, wmemValues);
reset(mMockNetd);
}
@Test
- public void testTcpBufferReset() {
+ public void testTcpBufferReset() throws Exception {
final String testTcpBufferSizes = "1,2,3,4,5,6";
- mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
reset(mMockNetd);
// Switching default network updates TCP buffer sizes.
mCellNetworkAgent.connect(false);
@@ -6066,18 +5715,18 @@
}
@Test
- public void testGetGlobalProxyForNetwork() {
+ public void testGetGlobalProxyForNetwork() throws Exception {
final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888);
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
final Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
when(mService.mProxyTracker.getGlobalProxy()).thenReturn(testProxyInfo);
assertEquals(testProxyInfo, mService.getProxyForNetwork(wifiNetwork));
}
@Test
- public void testGetProxyForActiveNetwork() {
+ public void testGetProxyForActiveNetwork() throws Exception {
final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888);
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
waitForIdle();
assertNull(mService.getProxyForNetwork(null));
@@ -6092,18 +5741,19 @@
}
@Test
- public void testGetProxyForVPN() {
+ public void testGetProxyForVPN() throws Exception {
final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888);
// Set up a WiFi network with no proxy
- mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
waitForIdle();
assertNull(mService.getProxyForNetwork(null));
// Set up a VPN network with a proxy
final int uid = Process.myUid();
- final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+ final TestNetworkAgentWrapper
+ vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
final ArraySet<UidRange> ranges = new ArraySet<>();
ranges.add(new UidRange(uid, uid));
mMockVpn.setUids(ranges);
@@ -6146,14 +5796,13 @@
}
@Test
- @Ignore
public void testFullyRoutedVpnResultsInInterfaceFilteringRules() throws Exception {
LinkProperties lp = new LinkProperties();
lp.setInterfaceName("tun0");
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
// The uid range needs to cover the test app so the network is visible to it.
final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
- final MockNetworkAgent vpnNetworkAgent = establishVpn(lp, VPN_UID, vpnRange);
+ final TestNetworkAgentWrapper vpnNetworkAgent = establishVpn(lp, VPN_UID, vpnRange);
// Connected VPN should have interface rules set up. There are two expected invocations,
// one during VPN uid update, one during VPN LinkProperties update
@@ -6173,21 +5822,20 @@
}
@Test
- @Ignore
public void testLegacyVpnDoesNotResultInInterfaceFilteringRule() throws Exception {
LinkProperties lp = new LinkProperties();
lp.setInterfaceName("tun0");
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
// The uid range needs to cover the test app so the network is visible to it.
final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
- final MockNetworkAgent vpnNetworkAgent = establishVpn(lp, Process.SYSTEM_UID, vpnRange);
+ final TestNetworkAgentWrapper vpnNetworkAgent = establishVpn(
+ lp, Process.SYSTEM_UID, vpnRange);
// Legacy VPN should not have interface rules set up
verify(mMockNetd, never()).firewallAddUidInterfaceRules(any(), any());
}
@Test
- @Ignore
public void testLocalIpv4OnlyVpnDoesNotResultInInterfaceFilteringRule()
throws Exception {
LinkProperties lp = new LinkProperties();
@@ -6196,21 +5844,21 @@
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
// The uid range needs to cover the test app so the network is visible to it.
final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
- final MockNetworkAgent vpnNetworkAgent = establishVpn(lp, Process.SYSTEM_UID, vpnRange);
+ final TestNetworkAgentWrapper vpnNetworkAgent = establishVpn(
+ lp, Process.SYSTEM_UID, vpnRange);
// IPv6 unreachable route should not be misinterpreted as a default route
verify(mMockNetd, never()).firewallAddUidInterfaceRules(any(), any());
}
@Test
- @Ignore
public void testVpnHandoverChangesInterfaceFilteringRule() throws Exception {
LinkProperties lp = new LinkProperties();
lp.setInterfaceName("tun0");
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
// The uid range needs to cover the test app so the network is visible to it.
final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
- final MockNetworkAgent vpnNetworkAgent = establishVpn(lp, VPN_UID, vpnRange);
+ final TestNetworkAgentWrapper vpnNetworkAgent = establishVpn(lp, VPN_UID, vpnRange);
// Connected VPN should have interface rules set up. There are two expected invocations,
// one during VPN uid update, one during VPN LinkProperties update
@@ -6253,14 +5901,13 @@
}
@Test
- @Ignore
public void testUidUpdateChangesInterfaceFilteringRule() throws Exception {
LinkProperties lp = new LinkProperties();
lp.setInterfaceName("tun0");
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
// The uid range needs to cover the test app so the network is visible to it.
final UidRange vpnRange = UidRange.createForUser(VPN_USER);
- final MockNetworkAgent vpnNetworkAgent = establishVpn(lp, VPN_UID,
+ final TestNetworkAgentWrapper vpnNetworkAgent = establishVpn(lp, VPN_UID,
Collections.singleton(vpnRange));
reset(mMockNetd);
@@ -6282,9 +5929,10 @@
}
- private MockNetworkAgent establishVpn(LinkProperties lp, int establishingUid,
- Set<UidRange> vpnRange) {
- final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN, lp);
+ private TestNetworkAgentWrapper establishVpn(LinkProperties lp, int establishingUid,
+ Set<UidRange> vpnRange) throws Exception {
+ final TestNetworkAgentWrapper
+ vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN, lp);
vpnNetworkAgent.getNetworkCapabilities().setEstablishingVpnAppUid(establishingUid);
mMockVpn.setNetworkAgent(vpnNetworkAgent);
mMockVpn.connect();
@@ -6294,14 +5942,6 @@
return vpnNetworkAgent;
}
- private void assertContainsExactly(int[] actual, int... expected) {
- int[] sortedActual = Arrays.copyOf(actual, actual.length);
- int[] sortedExpected = Arrays.copyOf(expected, expected.length);
- Arrays.sort(sortedActual);
- Arrays.sort(sortedExpected);
- assertArrayEquals(sortedExpected, sortedActual);
- }
-
private static PackageInfo buildPackageInfo(boolean hasSystemPermission, int uid) {
final PackageInfo packageInfo = new PackageInfo();
packageInfo.requestedPermissions = new String[0];
diff --git a/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt b/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt
new file mode 100644
index 0000000..f045369
--- /dev/null
+++ b/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+package com.android.server
+
+import android.net.ConnectivityManager.TYPE_ETHERNET
+import android.net.ConnectivityManager.TYPE_MOBILE
+import android.net.ConnectivityManager.TYPE_WIFI
+import android.net.ConnectivityManager.TYPE_WIMAX
+import android.net.NetworkInfo.DetailedState.CONNECTED
+import android.net.NetworkInfo.DetailedState.DISCONNECTED
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.server.ConnectivityService.LegacyTypeTracker
+import com.android.server.connectivity.NetworkAgentInfo
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNull
+import org.junit.Assert.assertSame
+import org.junit.Assert.assertTrue
+import org.junit.Assert.fail
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.reset
+import org.mockito.Mockito.verify
+
+const val UNSUPPORTED_TYPE = TYPE_WIMAX
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class LegacyTypeTrackerTest {
+ private val supportedTypes = arrayOf(TYPE_MOBILE, TYPE_WIFI, TYPE_ETHERNET)
+
+ private val mMockService = mock(ConnectivityService::class.java).apply {
+ doReturn(false).`when`(this).isDefaultNetwork(any())
+ }
+ private val mTracker = LegacyTypeTracker(mMockService).apply {
+ supportedTypes.forEach {
+ addSupportedType(it)
+ }
+ }
+
+ @Test
+ fun testSupportedTypes() {
+ try {
+ mTracker.addSupportedType(supportedTypes[0])
+ fail("Expected IllegalStateException")
+ } catch (expected: IllegalStateException) {}
+ supportedTypes.forEach {
+ assertTrue(mTracker.isTypeSupported(it))
+ }
+ assertFalse(mTracker.isTypeSupported(UNSUPPORTED_TYPE))
+ }
+
+ @Test
+ fun testAddNetwork() {
+ val mobileNai = mock(NetworkAgentInfo::class.java)
+ val wifiNai = mock(NetworkAgentInfo::class.java)
+ mTracker.add(TYPE_MOBILE, mobileNai)
+ mTracker.add(TYPE_WIFI, wifiNai)
+ assertSame(mTracker.getNetworkForType(TYPE_MOBILE), mobileNai)
+ assertSame(mTracker.getNetworkForType(TYPE_WIFI), wifiNai)
+ // Make sure adding a second NAI does not change the results.
+ val secondMobileNai = mock(NetworkAgentInfo::class.java)
+ mTracker.add(TYPE_MOBILE, secondMobileNai)
+ assertSame(mTracker.getNetworkForType(TYPE_MOBILE), mobileNai)
+ assertSame(mTracker.getNetworkForType(TYPE_WIFI), wifiNai)
+ // Make sure removing a network that wasn't added for this type is a no-op.
+ mTracker.remove(TYPE_MOBILE, wifiNai, false /* wasDefault */)
+ assertSame(mTracker.getNetworkForType(TYPE_MOBILE), mobileNai)
+ assertSame(mTracker.getNetworkForType(TYPE_WIFI), wifiNai)
+ // Remove the top network for mobile and make sure the second one becomes the network
+ // of record for this type.
+ mTracker.remove(TYPE_MOBILE, mobileNai, false /* wasDefault */)
+ assertSame(mTracker.getNetworkForType(TYPE_MOBILE), secondMobileNai)
+ assertSame(mTracker.getNetworkForType(TYPE_WIFI), wifiNai)
+ // Make sure adding a network for an unsupported type does not register it.
+ mTracker.add(UNSUPPORTED_TYPE, mobileNai)
+ assertNull(mTracker.getNetworkForType(UNSUPPORTED_TYPE))
+ }
+
+ @Test
+ fun testBroadcastOnDisconnect() {
+ val mobileNai1 = mock(NetworkAgentInfo::class.java)
+ val mobileNai2 = mock(NetworkAgentInfo::class.java)
+ doReturn(false).`when`(mMockService).isDefaultNetwork(mobileNai1)
+ mTracker.add(TYPE_MOBILE, mobileNai1)
+ verify(mMockService).sendLegacyNetworkBroadcast(mobileNai1, CONNECTED, TYPE_MOBILE)
+ reset(mMockService)
+ doReturn(false).`when`(mMockService).isDefaultNetwork(mobileNai2)
+ mTracker.add(TYPE_MOBILE, mobileNai2)
+ verify(mMockService, never()).sendLegacyNetworkBroadcast(any(), any(), anyInt())
+ mTracker.remove(TYPE_MOBILE, mobileNai1, false /* wasDefault */)
+ verify(mMockService).sendLegacyNetworkBroadcast(mobileNai1, DISCONNECTED, TYPE_MOBILE)
+ verify(mMockService).sendLegacyNetworkBroadcast(mobileNai2, CONNECTED, TYPE_MOBILE)
+ }
+}
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
index d5b2c87..3a07166 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
@@ -21,11 +21,8 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
@@ -59,16 +56,11 @@
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 java.io.PrintWriter;
import java.io.StringWriter;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.List;
@RunWith(AndroidJUnit4.class)
@SmallTest
@@ -98,48 +90,6 @@
}
@Test
- public void testLoggingEvents() throws Exception {
- IpConnectivityLog logger = new IpConnectivityLog(mMockService);
-
- assertTrue(logger.log(1, FAKE_EV));
- assertTrue(logger.log(2, FAKE_EV));
- assertTrue(logger.log(3, FAKE_EV));
-
- List<ConnectivityMetricsEvent> got = verifyEvents(3);
- assertEventsEqual(expectedEvent(1), got.get(0));
- assertEventsEqual(expectedEvent(2), got.get(1));
- assertEventsEqual(expectedEvent(3), got.get(2));
- }
-
- @Test
- public void testLoggingEventsWithMultipleCallers() throws Exception {
- IpConnectivityLog logger = new IpConnectivityLog(mMockService);
-
- final int nCallers = 10;
- final int nEvents = 10;
- for (int n = 0; n < nCallers; n++) {
- final int i = n;
- new Thread() {
- public void run() {
- for (int j = 0; j < nEvents; j++) {
- assertTrue(logger.log(1 + i * 100 + j, FAKE_EV));
- }
- }
- }.start();
- }
-
- List<ConnectivityMetricsEvent> got = verifyEvents(nCallers * nEvents, 200);
- Collections.sort(got, EVENT_COMPARATOR);
- Iterator<ConnectivityMetricsEvent> iter = got.iterator();
- for (int i = 0; i < nCallers; i++) {
- for (int j = 0; j < nEvents; j++) {
- int expectedTimestamp = 1 + i * 100 + j;
- assertEventsEqual(expectedEvent(expectedTimestamp), iter.next());
- }
- }
- }
-
- @Test
public void testBufferFlushing() {
String output1 = getdump("flush");
assertEquals("", output1);
@@ -653,16 +603,7 @@
return nai;
}
- List<ConnectivityMetricsEvent> verifyEvents(int n, int timeoutMs) throws Exception {
- ArgumentCaptor<ConnectivityMetricsEvent> captor =
- ArgumentCaptor.forClass(ConnectivityMetricsEvent.class);
- verify(mMockService, timeout(timeoutMs).times(n)).logEvent(captor.capture());
- return captor.getAllValues();
- }
- List<ConnectivityMetricsEvent> verifyEvents(int n) throws Exception {
- return verifyEvents(n, 10);
- }
static void verifySerialization(String want, String output) {
try {
@@ -674,28 +615,4 @@
fail(e.toString());
}
}
-
- static String joinLines(String ... elems) {
- StringBuilder b = new StringBuilder();
- for (String s : elems) {
- b.append(s).append("\n");
- }
- return b.toString();
- }
-
- static ConnectivityMetricsEvent expectedEvent(int timestamp) {
- ConnectivityMetricsEvent ev = new ConnectivityMetricsEvent();
- ev.timestamp = timestamp;
- ev.data = FAKE_EV;
- return ev;
- }
-
- /** Outer equality for ConnectivityMetricsEvent to avoid overriding equals() and hashCode(). */
- static void assertEventsEqual(ConnectivityMetricsEvent expected, ConnectivityMetricsEvent got) {
- assertEquals(expected.timestamp, got.timestamp);
- assertEquals(expected.data, got.data);
- }
-
- static final Comparator<ConnectivityMetricsEvent> EVENT_COMPARATOR =
- Comparator.comparingLong((ev) -> ev.timestamp);
}
diff --git a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
index e4117b8..aef9386 100644
--- a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
@@ -19,8 +19,9 @@
import static android.net.metrics.INetdEventListener.EVENT_GETADDRINFO;
import static android.net.metrics.INetdEventListener.EVENT_GETHOSTBYNAME;
+import static com.android.testutils.MiscAssertsKt.assertStringContains;
+
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -111,15 +112,15 @@
String[] events2 = remove(listNetdEvent(), baseline);
int expectedLength2 = uids.length + 1; // +1 for the WakeupStats line
assertEquals(expectedLength2, events2.length);
- assertContains(events2[0], "WakeupStats");
- assertContains(events2[0], "wlan0");
- assertContains(events2[0], "0x800");
- assertContains(events2[0], "0x86dd");
+ assertStringContains(events2[0], "WakeupStats");
+ assertStringContains(events2[0], "wlan0");
+ assertStringContains(events2[0], "0x800");
+ assertStringContains(events2[0], "0x86dd");
for (int i = 0; i < uids.length; i++) {
String got = events2[i+1];
- assertContains(got, "WakeupEvent");
- assertContains(got, "wlan0");
- assertContains(got, "uid: " + uids[i]);
+ assertStringContains(got, "WakeupEvent");
+ assertStringContains(got, "wlan0");
+ assertStringContains(got, "uid: " + uids[i]);
}
int uid = 20000;
@@ -131,13 +132,13 @@
String[] events3 = remove(listNetdEvent(), baseline);
int expectedLength3 = BUFFER_LENGTH + 1; // +1 for the WakeupStats line
assertEquals(expectedLength3, events3.length);
- assertContains(events2[0], "WakeupStats");
- assertContains(events2[0], "wlan0");
+ assertStringContains(events2[0], "WakeupStats");
+ assertStringContains(events2[0], "wlan0");
for (int i = 1; i < expectedLength3; i++) {
String got = events3[i];
- assertContains(got, "WakeupEvent");
- assertContains(got, "wlan0");
- assertContains(got, "uid: " + uid);
+ assertStringContains(got, "WakeupEvent");
+ assertStringContains(got, "wlan0");
+ assertStringContains(got, "uid: " + uid);
}
uid = 45678;
@@ -145,9 +146,9 @@
String[] events4 = remove(listNetdEvent(), baseline);
String lastEvent = events4[events4.length - 1];
- assertContains(lastEvent, "WakeupEvent");
- assertContains(lastEvent, "wlan0");
- assertContains(lastEvent, "uid: " + uid);
+ assertStringContains(lastEvent, "WakeupEvent");
+ assertStringContains(lastEvent, "wlan0");
+ assertStringContains(lastEvent, "uid: " + uid);
}
@Test
@@ -529,10 +530,6 @@
return buffer.toString().split("\\n");
}
- static void assertContains(String got, String want) {
- assertTrue(got + " did not contain \"" + want + "\"", got.contains(want));
- }
-
static <T> T[] remove(T[] array, T[] filtered) {
List<T> c = Arrays.asList(filtered);
int next = 0;
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index 62a4718..cd2bd26 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -65,6 +65,7 @@
import android.os.UserManager;
import android.util.SparseIntArray;
+import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -96,6 +97,7 @@
private static final int SYSTEM_UID1 = 1000;
private static final int SYSTEM_UID2 = 1008;
private static final int VPN_UID = 10002;
+ private static final String REAL_SYSTEM_PACKAGE_NAME = "android";
private static final String MOCK_PACKAGE1 = "appName1";
private static final String MOCK_PACKAGE2 = "appName2";
private static final String SYSTEM_PACKAGE1 = "sysName1";
@@ -188,8 +190,10 @@
private static PackageInfo buildPackageInfo(boolean hasSystemPermission, int uid, int userId) {
final PackageInfo pkgInfo;
if (hasSystemPermission) {
- pkgInfo = packageInfoWithPermissions(new String[] {CHANGE_NETWORK_STATE, NETWORK_STACK},
- PARTITION_SYSTEM);
+ final String[] systemPermissions = new String[]{
+ CHANGE_NETWORK_STATE, NETWORK_STACK, CONNECTIVITY_USE_RESTRICTED_NETWORKS
+ };
+ pkgInfo = packageInfoWithPermissions(systemPermissions, PARTITION_SYSTEM);
} else {
pkgInfo = packageInfoWithPermissions(new String[] {}, "");
}
@@ -524,7 +528,7 @@
SparseIntArray netdPermissionsAppIds = new SparseIntArray();
netdPermissionsAppIds.put(MOCK_UID1, INetd.PERMISSION_INTERNET);
- netdPermissionsAppIds.put(MOCK_UID2, INetd.NO_PERMISSIONS);
+ netdPermissionsAppIds.put(MOCK_UID2, INetd.PERMISSION_NONE);
netdPermissionsAppIds.put(SYSTEM_UID1, INetd.PERMISSION_INTERNET
| INetd.PERMISSION_UPDATE_DEVICE_STATS);
netdPermissionsAppIds.put(SYSTEM_UID2, INetd.PERMISSION_UPDATE_DEVICE_STATS);
@@ -534,7 +538,7 @@
mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET,
new int[]{MOCK_UID1});
- mNetdServiceMonitor.expectPermission(INetd.NO_PERMISSIONS, new int[]{MOCK_UID2});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, 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,
@@ -553,8 +557,8 @@
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});
+ mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID1, INetd.PERMISSION_NONE);
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{SYSTEM_UID1});
}
private PackageInfo addPackage(String packageName, int uid, String[] permissions)
@@ -646,4 +650,16 @@
mObserver.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
}
+
+ @Test
+ public void testRealSystemPermission() throws Exception {
+ // Use the real context as this test must ensure the *real* system package holds the
+ // necessary permission.
+ final Context realContext = InstrumentationRegistry.getContext();
+ final PermissionMonitor monitor = new PermissionMonitor(realContext, mNetdService);
+ final PackageManager manager = realContext.getPackageManager();
+ final PackageInfo systemInfo = manager.getPackageInfo(REAL_SYSTEM_PACKAGE_NAME,
+ GET_PERMISSIONS | MATCH_ANY_USER);
+ assertTrue(monitor.hasPermission(systemInfo, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+ }
}
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 2cae250..ce50bef 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -727,94 +727,4 @@
"::/1", "8000::/2", "c000::/3", "e000::/4", "f000::/5", "f800::/6",
"fe00::/8", "2605:ef80:e:af1d::/64");
}
-
- @Test
- public void testProvidesRoutesToMostDestinations() {
- final LinkProperties lp = new LinkProperties();
-
- // Default route provides routes to all IPv4 destinations.
- lp.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0")));
- assertTrue(Vpn.providesRoutesToMostDestinations(lp));
-
- // Empty LP provides routes to no destination
- lp.clear();
- assertFalse(Vpn.providesRoutesToMostDestinations(lp));
-
- // All IPv4 routes except for local networks. This is the case most relevant
- // to this function. It provides routes to almost the entire space.
- // (clone the stream so that we can reuse it later)
- publicIpV4Routes().forEach(s -> lp.addRoute(new RouteInfo(new IpPrefix(s))));
- assertTrue(Vpn.providesRoutesToMostDestinations(lp));
-
- // Removing a 16-bit prefix, which is 65536 addresses. This is still enough to
- // provide routes to "most" destinations.
- lp.removeRoute(new RouteInfo(new IpPrefix("192.169.0.0/16")));
- assertTrue(Vpn.providesRoutesToMostDestinations(lp));
-
- // Remove the /2 route, which represent a quarter of the available routing space.
- // This LP does not provides routes to "most" destinations any more.
- lp.removeRoute(new RouteInfo(new IpPrefix("64.0.0.0/2")));
- assertFalse(Vpn.providesRoutesToMostDestinations(lp));
-
- lp.clear();
- publicIpV6Routes().forEach(s -> lp.addRoute(new RouteInfo(new IpPrefix(s))));
- assertTrue(Vpn.providesRoutesToMostDestinations(lp));
-
- lp.removeRoute(new RouteInfo(new IpPrefix("::/1")));
- assertFalse(Vpn.providesRoutesToMostDestinations(lp));
-
- // V6 does not provide sufficient coverage but v4 does
- publicIpV4Routes().forEach(s -> lp.addRoute(new RouteInfo(new IpPrefix(s))));
- assertTrue(Vpn.providesRoutesToMostDestinations(lp));
-
- // V4 still does
- lp.removeRoute(new RouteInfo(new IpPrefix("192.169.0.0/16")));
- assertTrue(Vpn.providesRoutesToMostDestinations(lp));
-
- // V4 does not any more
- lp.removeRoute(new RouteInfo(new IpPrefix("64.0.0.0/2")));
- assertFalse(Vpn.providesRoutesToMostDestinations(lp));
-
- // V4 does not, but V6 has sufficient coverage again
- lp.addRoute(new RouteInfo(new IpPrefix("::/1")));
- assertTrue(Vpn.providesRoutesToMostDestinations(lp));
-
- lp.clear();
- // V4-unreachable route should not be treated as sufficient coverage
- lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
- assertFalse(Vpn.providesRoutesToMostDestinations(lp));
-
- lp.clear();
- // V6-unreachable route should not be treated as sufficient coverage
- lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
- assertFalse(Vpn.providesRoutesToMostDestinations(lp));
- }
-
- @Test
- public void testDoesNotLockUpWithTooManyRoutes() {
- final LinkProperties lp = new LinkProperties();
- final byte[] ad = new byte[4];
- // Actually evaluating this many routes under 1500ms is impossible on
- // current hardware and for some time, as the algorithm is O(n²).
- // Make sure the system has a safeguard against this and does not
- // lock up.
- final int MAX_ROUTES = 4000;
- final long MAX_ALLOWED_TIME_MS = 1500;
- for (int i = 0; i < MAX_ROUTES; ++i) {
- ad[0] = (byte)((i >> 24) & 0xFF);
- ad[1] = (byte)((i >> 16) & 0xFF);
- ad[2] = (byte)((i >> 8) & 0xFF);
- ad[3] = (byte)(i & 0xFF);
- try {
- lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.getByAddress(ad), 32)));
- } catch (UnknownHostException e) {
- // UnknownHostException is only thrown for an address of illegal length,
- // which can't happen in the case above.
- }
- }
- final long start = SystemClock.currentThreadTimeMillis();
- assertTrue(Vpn.providesRoutesToMostDestinations(lp));
- final long end = SystemClock.currentThreadTimeMillis();
- assertTrue(end - start < MAX_ALLOWED_TIME_MS);
- }
}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsAccessTest.java b/tests/net/java/com/android/server/net/NetworkStatsAccessTest.java
index 6e725dd..858358c 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsAccessTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsAccessTest.java
@@ -161,7 +161,7 @@
}
private void setHasCarrierPrivileges(boolean hasPrivileges) {
- when(mTm.checkCarrierPrivilegesForPackage(TEST_PKG)).thenReturn(
+ when(mTm.checkCarrierPrivilegesForPackageAnyPhone(TEST_PKG)).thenReturn(
hasPrivileges ? TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS
: TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java b/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java
new file mode 100644
index 0000000..28785f7
--- /dev/null
+++ b/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.net;
+
+import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
+import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
+import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
+import static android.net.NetworkStats.METERED_ALL;
+import static android.net.NetworkStats.METERED_NO;
+import static android.net.NetworkStats.METERED_YES;
+import static android.net.NetworkStats.ROAMING_ALL;
+import static android.net.NetworkStats.ROAMING_NO;
+import static android.net.NetworkStats.ROAMING_YES;
+import static android.net.NetworkStats.SET_ALL;
+import static android.net.NetworkStats.SET_DEFAULT;
+import static android.net.NetworkStats.SET_FOREGROUND;
+import static android.net.NetworkStats.TAG_NONE;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.NetworkStats;
+
+import com.android.internal.net.VpnInfo;
+
+/** Superclass with utilities for NetworkStats(Service|Factory)Test */
+abstract class NetworkStatsBaseTest {
+ static final String TEST_IFACE = "test0";
+ static final String TEST_IFACE2 = "test1";
+ static final String TUN_IFACE = "test_nss_tun0";
+
+ static final int UID_RED = 1001;
+ static final int UID_BLUE = 1002;
+ static final int UID_GREEN = 1003;
+ static final int UID_VPN = 1004;
+
+ void assertValues(NetworkStats stats, String iface, int uid, long rxBytes,
+ long rxPackets, long txBytes, long txPackets) {
+ assertValues(
+ stats, iface, uid, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL,
+ rxBytes, rxPackets, txBytes, txPackets, 0);
+ }
+
+ void assertValues(NetworkStats stats, String iface, int uid, int set, int tag,
+ int metered, int roaming, int defaultNetwork, long rxBytes, long rxPackets,
+ long txBytes, long txPackets, long operations) {
+ final NetworkStats.Entry entry = new NetworkStats.Entry();
+ final int[] sets;
+ if (set == SET_ALL) {
+ sets = new int[] {SET_ALL, SET_DEFAULT, SET_FOREGROUND};
+ } else {
+ sets = new int[] {set};
+ }
+
+ final int[] roamings;
+ if (roaming == ROAMING_ALL) {
+ roamings = new int[] {ROAMING_ALL, ROAMING_YES, ROAMING_NO};
+ } else {
+ roamings = new int[] {roaming};
+ }
+
+ final int[] meterings;
+ if (metered == METERED_ALL) {
+ meterings = new int[] {METERED_ALL, METERED_YES, METERED_NO};
+ } else {
+ meterings = new int[] {metered};
+ }
+
+ final int[] defaultNetworks;
+ if (defaultNetwork == DEFAULT_NETWORK_ALL) {
+ defaultNetworks =
+ new int[] {DEFAULT_NETWORK_ALL, DEFAULT_NETWORK_YES, DEFAULT_NETWORK_NO};
+ } else {
+ defaultNetworks = new int[] {defaultNetwork};
+ }
+
+ for (int s : sets) {
+ for (int r : roamings) {
+ for (int m : meterings) {
+ for (int d : defaultNetworks) {
+ final int i = stats.findIndex(iface, uid, s, tag, m, r, d);
+ if (i != -1) {
+ entry.add(stats.getValues(i, null));
+ }
+ }
+ }
+ }
+ }
+
+ assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
+ assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
+ assertEquals("unexpected txBytes", txBytes, entry.txBytes);
+ assertEquals("unexpected txPackets", txPackets, entry.txPackets);
+ assertEquals("unexpected operations", operations, entry.operations);
+ }
+
+ VpnInfo createVpnInfo(String[] underlyingIfaces) {
+ VpnInfo info = new VpnInfo();
+ info.ownerUid = UID_VPN;
+ info.vpnIface = TUN_IFACE;
+ info.underlyingIfaces = underlyingIfaces;
+ return info;
+ }
+}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
index 9b4f49c..8f90f13 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
@@ -29,6 +29,7 @@
import static com.android.server.net.NetworkStatsCollection.multiplySafe;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
@@ -43,7 +44,6 @@
import android.os.UserHandle;
import android.telephony.SubscriptionPlan;
import android.telephony.TelephonyManager;
-import android.test.MoreAsserts;
import android.text.format.DateUtils;
import android.util.RecurrenceRule;
@@ -240,11 +240,11 @@
60 * MINUTE_IN_MILLIS, entry);
// Verify the set of relevant UIDs for each access level.
- MoreAsserts.assertEquals(new int[] { myUid },
+ assertArrayEquals(new int[] { myUid },
collection.getRelevantUids(NetworkStatsAccess.Level.DEFAULT));
- MoreAsserts.assertEquals(new int[] { Process.SYSTEM_UID, myUid, otherUidInSameUser },
+ assertArrayEquals(new int[] { Process.SYSTEM_UID, myUid, otherUidInSameUser },
collection.getRelevantUids(NetworkStatsAccess.Level.USER));
- MoreAsserts.assertEquals(
+ assertArrayEquals(
new int[] { Process.SYSTEM_UID, myUid, otherUidInSameUser, uidInDifferentUser },
collection.getRelevantUids(NetworkStatsAccess.Level.DEVICE));
diff --git a/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java b/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java
index 95bc7d9..a21f509 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java
@@ -16,8 +16,11 @@
package com.android.server.net;
+import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
+import static android.net.NetworkStats.METERED_ALL;
import static android.net.NetworkStats.METERED_NO;
+import static android.net.NetworkStats.ROAMING_ALL;
import static android.net.NetworkStats.ROAMING_NO;
import static android.net.NetworkStats.SET_ALL;
import static android.net.NetworkStats.SET_DEFAULT;
@@ -39,6 +42,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.frameworks.tests.net.R;
+import com.android.internal.net.VpnInfo;
import libcore.io.IoUtils;
import libcore.io.Streams;
@@ -54,12 +58,12 @@
import java.io.InputStream;
import java.io.OutputStream;
-/**
- * Tests for {@link NetworkStatsFactory}.
- */
+/** Tests for {@link NetworkStatsFactory}. */
@RunWith(AndroidJUnit4.class)
@SmallTest
-public class NetworkStatsFactoryTest {
+public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
+ private static final String CLAT_PREFIX = "v4-";
+
private File mTestProc;
private NetworkStatsFactory mFactory;
@@ -75,6 +79,7 @@
// related to networkStatsFactory is compiled to a minimal native library and loaded here.
System.loadLibrary("networkstatsfactorytestjni");
mFactory = new NetworkStatsFactory(mTestProc, false);
+ mFactory.updateVpnInfos(new VpnInfo[0]);
}
@After
@@ -99,6 +104,236 @@
}
@Test
+ public void vpnRewriteTrafficThroughItself() throws Exception {
+ VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
+ mFactory.updateVpnInfos(vpnInfos);
+
+ // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
+ // overhead per packet):
+ //
+ // 1000 bytes (100 packets) were sent, and 2000 bytes (200 packets) were received by UID_RED
+ // over VPN.
+ // 500 bytes (50 packets) were sent, and 1000 bytes (100 packets) were received by UID_BLUE
+ // over VPN.
+ //
+ // VPN UID rewrites packets read from TUN back to TUN, plus some of its own traffic
+
+ final NetworkStats tunStats = parseDetailedStats(R.raw.xt_qtaguid_vpn_rewrite_through_self);
+
+ assertValues(tunStats, TUN_IFACE, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
+ DEFAULT_NETWORK_ALL, 2000L, 200L, 1000L, 100L, 0);
+ assertValues(tunStats, TUN_IFACE, UID_BLUE, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
+ DEFAULT_NETWORK_ALL, 1000L, 100L, 500L, 50L, 0);
+ assertValues(tunStats, TUN_IFACE, UID_VPN, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
+ DEFAULT_NETWORK_ALL, 0L, 0L, 1600L, 160L, 0);
+
+ assertValues(tunStats, TEST_IFACE, UID_RED, 2000L, 200L, 1000L, 100L);
+ assertValues(tunStats, TEST_IFACE, UID_BLUE, 1000L, 100L, 500L, 50L);
+ assertValues(tunStats, TEST_IFACE, UID_VPN, 300L, 0L, 260L, 26L);
+ }
+
+ @Test
+ public void vpnWithClat() throws Exception {
+ VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {CLAT_PREFIX + TEST_IFACE})};
+ mFactory.updateVpnInfos(vpnInfos);
+ mFactory.noteStackedIface(CLAT_PREFIX + TEST_IFACE, TEST_IFACE);
+
+ // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
+ // overhead per packet):
+ // 1000 bytes (100 packets) were sent, and 2000 bytes (200 packets) were received by UID_RED
+ // over VPN.
+ // 500 bytes (50 packets) were sent, and 1000 bytes (100 packets) were received by UID_BLUE
+ // over VPN.
+ // VPN sent 1650 bytes (150 packets), and received 3300 (300 packets) over v4-WiFi, and clat
+ // added 20 bytes per packet of extra overhead
+ //
+ // For 1650 bytes sent over v4-WiFi, 4650 bytes were actually sent over WiFi, which is
+ // expected to be split as follows:
+ // UID_RED: 1000 bytes, 100 packets
+ // UID_BLUE: 500 bytes, 50 packets
+ // UID_VPN: 3150 bytes, 0 packets
+ //
+ // For 3300 bytes received over v4-WiFi, 9300 bytes were actually sent over WiFi, which is
+ // expected to be split as follows:
+ // UID_RED: 2000 bytes, 200 packets
+ // UID_BLUE: 1000 bytes, 100 packets
+ // UID_VPN: 6300 bytes, 0 packets
+ final NetworkStats tunStats = parseDetailedStats(R.raw.xt_qtaguid_vpn_with_clat);
+
+ assertValues(tunStats, CLAT_PREFIX + TEST_IFACE, UID_RED, 2000L, 200L, 1000, 100L);
+ assertValues(tunStats, CLAT_PREFIX + TEST_IFACE, UID_BLUE, 1000L, 100L, 500L, 50L);
+ assertValues(tunStats, CLAT_PREFIX + TEST_IFACE, UID_VPN, 6300L, 0L, 3150L, 0L);
+ }
+
+ @Test
+ public void vpnWithOneUnderlyingIface() throws Exception {
+ VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
+ mFactory.updateVpnInfos(vpnInfos);
+
+ // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
+ // overhead per packet):
+ // 1000 bytes (100 packets) were sent, and 2000 bytes (200 packets) were received by UID_RED
+ // over VPN.
+ // 500 bytes (50 packets) were sent, and 1000 bytes (100 packets) were received by UID_BLUE
+ // over VPN.
+ // VPN sent 1650 bytes (150 packets), and received 3300 (300 packets) over WiFi.
+ // Of 1650 bytes sent over WiFi, expect 1000 bytes attributed to UID_RED, 500 bytes
+ // attributed to UID_BLUE, and 150 bytes attributed to UID_VPN.
+ // Of 3300 bytes received over WiFi, expect 2000 bytes attributed to UID_RED, 1000 bytes
+ // attributed to UID_BLUE, and 300 bytes attributed to UID_VPN.
+ final NetworkStats tunStats = parseDetailedStats(R.raw.xt_qtaguid_vpn_one_underlying);
+
+ assertValues(tunStats, TEST_IFACE, UID_RED, 2000L, 200L, 1000L, 100L);
+ assertValues(tunStats, TEST_IFACE, UID_BLUE, 1000L, 100L, 500L, 50L);
+ assertValues(tunStats, TEST_IFACE, UID_VPN, 300L, 0L, 150L, 0L);
+ }
+
+ @Test
+ public void vpnWithOneUnderlyingIfaceAndOwnTraffic() throws Exception {
+ // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE).
+ VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
+ mFactory.updateVpnInfos(vpnInfos);
+
+ // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
+ // overhead per packet):
+ // 1000 bytes (100 packets) were sent, and 2000 bytes (200 packets) were received by UID_RED
+ // over VPN.
+ // 500 bytes (50 packets) were sent, and 1000 bytes (100 packets) were received by UID_BLUE
+ // over VPN.
+ // Additionally, the VPN sends 6000 bytes (600 packets) of its own traffic into the tun
+ // interface (passing that traffic to the VPN endpoint), and receives 5000 bytes (500
+ // packets) from it. Including overhead that is 6600/5500 bytes.
+ // VPN sent 8250 bytes (750 packets), and received 8800 (800 packets) over WiFi.
+ // Of 8250 bytes sent over WiFi, expect 1000 bytes attributed to UID_RED, 500 bytes
+ // attributed to UID_BLUE, and 6750 bytes attributed to UID_VPN.
+ // Of 8800 bytes received over WiFi, expect 2000 bytes attributed to UID_RED, 1000 bytes
+ // attributed to UID_BLUE, and 5800 bytes attributed to UID_VPN.
+ final NetworkStats tunStats =
+ parseDetailedStats(R.raw.xt_qtaguid_vpn_one_underlying_own_traffic);
+
+ assertValues(tunStats, TEST_IFACE, UID_RED, 2000L, 200L, 1000L, 100L);
+ assertValues(tunStats, TEST_IFACE, UID_BLUE, 1000L, 100L, 500L, 50L);
+ assertValues(tunStats, TEST_IFACE, UID_VPN, 5800L, 500L, 6750L, 600L);
+ }
+
+ @Test
+ public void vpnWithOneUnderlyingIface_withCompression() throws Exception {
+ // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE).
+ VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
+ mFactory.updateVpnInfos(vpnInfos);
+
+ // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
+ // overhead per packet):
+ // 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
+ // 3000 bytes (300 packets) were sent/received by UID_BLUE over VPN.
+ // VPN sent/received 1000 bytes (100 packets) over WiFi.
+ // Of 1000 bytes over WiFi, expect 250 bytes attributed UID_RED and 750 bytes to UID_BLUE,
+ // with nothing attributed to UID_VPN for both rx/tx traffic.
+ final NetworkStats tunStats =
+ parseDetailedStats(R.raw.xt_qtaguid_vpn_one_underlying_compression);
+
+ assertValues(tunStats, TEST_IFACE, UID_RED, 250L, 25L, 250L, 25L);
+ assertValues(tunStats, TEST_IFACE, UID_BLUE, 750L, 75L, 750L, 75L);
+ assertValues(tunStats, TEST_IFACE, UID_VPN, 0L, 0L, 0L, 0L);
+ }
+
+ @Test
+ public void vpnWithTwoUnderlyingIfaces_packetDuplication() throws Exception {
+ // WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and
+ // Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set.
+ // Additionally, VPN is duplicating traffic across both WiFi and Cell.
+ VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
+ mFactory.updateVpnInfos(vpnInfos);
+
+ // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
+ // overhead per packet):
+ // 1000 bytes (100 packets) were sent/received by UID_RED and UID_BLUE over VPN.
+ // VPN sent/received 4400 bytes (400 packets) over both WiFi and Cell (8800 bytes in total).
+ // Of 8800 bytes over WiFi/Cell, expect:
+ // - 500 bytes rx/tx each over WiFi/Cell attributed to both UID_RED and UID_BLUE.
+ // - 1200 bytes rx/tx each over WiFi/Cell for VPN_UID.
+ final NetworkStats tunStats =
+ parseDetailedStats(R.raw.xt_qtaguid_vpn_two_underlying_duplication);
+
+ assertValues(tunStats, TEST_IFACE, UID_RED, 500L, 50L, 500L, 50L);
+ assertValues(tunStats, TEST_IFACE, UID_BLUE, 500L, 50L, 500L, 50L);
+ assertValues(tunStats, TEST_IFACE, UID_VPN, 1200L, 100L, 1200L, 100L);
+ assertValues(tunStats, TEST_IFACE2, UID_RED, 500L, 50L, 500L, 50L);
+ assertValues(tunStats, TEST_IFACE2, UID_BLUE, 500L, 50L, 500L, 50L);
+ assertValues(tunStats, TEST_IFACE2, UID_VPN, 1200L, 100L, 1200L, 100L);
+ }
+
+ @Test
+ public void vpnWithTwoUnderlyingIfaces_splitTraffic() throws Exception {
+ // WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and
+ // Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set.
+ // Additionally, VPN is arbitrarily splitting traffic across WiFi and Cell.
+ VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
+ mFactory.updateVpnInfos(vpnInfos);
+
+ // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
+ // overhead per packet):
+ // 1000 bytes (100 packets) were sent, and 500 bytes (50 packets) received by UID_RED over
+ // VPN.
+ // VPN sent 660 bytes (60 packets) over WiFi and 440 bytes (40 packets) over Cell.
+ // And, it received 330 bytes (30 packets) over WiFi and 220 bytes (20 packets) over Cell.
+ // For UID_RED, expect 600 bytes attributed over WiFi and 400 bytes over Cell for sent (tx)
+ // traffic. For received (rx) traffic, expect 300 bytes over WiFi and 200 bytes over Cell.
+ //
+ // For UID_VPN, expect 60 bytes attributed over WiFi and 40 bytes over Cell for tx traffic.
+ // And, 30 bytes over WiFi and 20 bytes over Cell for rx traffic.
+ final NetworkStats tunStats = parseDetailedStats(R.raw.xt_qtaguid_vpn_two_underlying_split);
+
+ assertValues(tunStats, TEST_IFACE, UID_RED, 300L, 30L, 600L, 60L);
+ assertValues(tunStats, TEST_IFACE, UID_VPN, 30L, 0L, 60L, 0L);
+ assertValues(tunStats, TEST_IFACE2, UID_RED, 200L, 20L, 400L, 40L);
+ assertValues(tunStats, TEST_IFACE2, UID_VPN, 20L, 0L, 40L, 0L);
+ }
+
+ @Test
+ public void vpnWithTwoUnderlyingIfaces_splitTrafficWithCompression() throws Exception {
+ // WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and
+ // Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set.
+ // Additionally, VPN is arbitrarily splitting compressed traffic across WiFi and Cell.
+ VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
+ mFactory.updateVpnInfos(vpnInfos);
+
+ // create some traffic (assume 10 bytes of MTU for VPN interface:
+ // 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
+ // VPN sent/received 600 bytes (60 packets) over WiFi and 200 bytes (20 packets) over Cell.
+ // For UID_RED, expect 600 bytes attributed over WiFi and 200 bytes over Cell for both
+ // rx/tx.
+ // UID_VPN gets nothing attributed to it (avoiding negative stats).
+ final NetworkStats tunStats =
+ parseDetailedStats(R.raw.xt_qtaguid_vpn_two_underlying_split_compression);
+
+ assertValues(tunStats, TEST_IFACE, UID_RED, 600L, 60L, 600L, 60L);
+ assertValues(tunStats, TEST_IFACE, UID_VPN, 0L, 0L, 0L, 0L);
+ assertValues(tunStats, TEST_IFACE2, UID_RED, 200L, 20L, 200L, 20L);
+ assertValues(tunStats, TEST_IFACE2, UID_VPN, 0L, 0L, 0L, 0L);
+ }
+
+ @Test
+ public void vpnWithIncorrectUnderlyingIface() throws Exception {
+ // WiFi and Cell networks are connected and VPN is using Cell (which has TEST_IFACE2),
+ // but has declared only WiFi (TEST_IFACE) in its underlying network set.
+ VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
+ mFactory.updateVpnInfos(vpnInfos);
+
+ // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
+ // overhead per packet):
+ // 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
+ // VPN sent/received 1100 bytes (100 packets) over Cell.
+ // Of 1100 bytes over Cell, expect all of it attributed to UID_VPN for both rx/tx traffic.
+ final NetworkStats tunStats = parseDetailedStats(R.raw.xt_qtaguid_vpn_incorrect_iface);
+
+ assertValues(tunStats, TEST_IFACE, UID_RED, 0L, 0L, 0L, 0L);
+ assertValues(tunStats, TEST_IFACE, UID_VPN, 0L, 0L, 0L, 0L);
+ assertValues(tunStats, TEST_IFACE2, UID_RED, 0L, 0L, 0L, 0L);
+ assertValues(tunStats, TEST_IFACE2, UID_VPN, 1100L, 100L, 1100L, 100L);
+ }
+
+ @Test
public void testKernelTags() throws Exception {
assertEquals(0, kernelToTag("0x0000000000000000"));
assertEquals(0x32, kernelToTag("0x0000003200000000"));
@@ -146,20 +381,25 @@
}
@Test
- public void testDoubleClatAccounting() throws Exception {
- NetworkStatsFactory.noteStackedIface("v4-wlan0", "wlan0");
+ public void testDoubleClatAccountingSimple() throws Exception {
+ mFactory.noteStackedIface("v4-wlan0", "wlan0");
// xt_qtaguid_with_clat_simple is a synthetic file that simulates
// - 213 received 464xlat packets of size 200 bytes
// - 41 sent 464xlat packets of size 100 bytes
// - no other traffic on base interface for root uid.
NetworkStats stats = parseDetailedStats(R.raw.xt_qtaguid_with_clat_simple);
- assertEquals(4, stats.size());
+ assertEquals(3, stats.size());
assertStatsEntry(stats, "v4-wlan0", 10060, SET_DEFAULT, 0x0, 46860L, 4920L);
assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, 0L, 0L);
+ }
- stats = parseDetailedStats(R.raw.xt_qtaguid_with_clat);
+ @Test
+ public void testDoubleClatAccounting() throws Exception {
+ mFactory.noteStackedIface("v4-wlan0", "wlan0");
+
+ NetworkStats stats = parseDetailedStats(R.raw.xt_qtaguid_with_clat);
assertEquals(42, stats.size());
assertStatsEntry(stats, "v4-wlan0", 0, SET_DEFAULT, 0x0, 356L, 276L);
@@ -178,8 +418,6 @@
assertStatsEntry(stats, "lo", 0, SET_DEFAULT, 0x0, 1288L, 1288L);
assertNoStatsEntry(stats, "wlan0", 1029, SET_DEFAULT, 0x0);
-
- NetworkStatsFactory.clearStackedIfaces();
}
@Test
@@ -194,7 +432,7 @@
long rootRxBytesAfter = 1398634L;
assertEquals("UID 0 traffic should be ~0", 4623, rootRxBytesAfter - rootRxBytesBefore);
- NetworkStatsFactory.noteStackedIface("v4-wlan0", "wlan0");
+ mFactory.noteStackedIface("v4-wlan0", "wlan0");
NetworkStats stats;
// Stats snapshot before the download
@@ -206,8 +444,6 @@
stats = parseDetailedStats(R.raw.xt_qtaguid_with_clat_100mb_download_after);
assertStatsEntry(stats, "v4-wlan0", 10106, SET_FOREGROUND, 0x0, appRxBytesAfter, 7867488L);
assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, rootRxBytesAfter, 0L);
-
- NetworkStatsFactory.clearStackedIfaces();
}
/**
@@ -272,11 +508,19 @@
private static void assertStatsEntry(NetworkStats stats, String iface, int uid, int set,
int tag, long rxBytes, long rxPackets, long txBytes, long txPackets) {
- final int i = stats.findIndex(iface, uid, set, tag, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO);
+ assertStatsEntry(stats, iface, uid, set, tag, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO,
+ rxBytes, rxPackets, txBytes, txPackets);
+ }
+
+ private static void assertStatsEntry(NetworkStats stats, String iface, int uid, int set,
+ int tag, int metered, int roaming, int defaultNetwork, long rxBytes, long rxPackets,
+ long txBytes, long txPackets) {
+ final int i = stats.findIndex(iface, uid, set, tag, metered, roaming, defaultNetwork);
+
if (i < 0) {
- fail(String.format("no NetworkStats for (iface: %s, uid: %d, set: %d, tag: %d)",
- iface, uid, set, tag));
+ fail(String.format("no NetworkStats for (iface: %s, uid: %d, set: %d, tag: %d, metered:"
+ + " %d, roaming: %d, defaultNetwork: %d)",
+ iface, uid, set, tag, metered, roaming, defaultNetwork));
}
final NetworkStats.Entry entry = stats.getValues(i, null);
assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
diff --git a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java b/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
index 43a3803..c0f9dc1 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
@@ -28,8 +28,6 @@
import static android.net.TrafficStats.MB_IN_BYTES;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
-import static com.android.internal.util.TestUtils.waitForIdleHandler;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
@@ -54,8 +52,8 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.internal.net.VpnInfo;
import com.android.server.net.NetworkStatsServiceTest.LatchedHandler;
+import com.android.testutils.HandlerUtilsKt;
import org.junit.Before;
import org.junit.Test;
@@ -94,8 +92,6 @@
private static final long BASE_BYTES = 7 * MB_IN_BYTES;
private static final int INVALID_TYPE = -1;
- private static final VpnInfo[] VPN_INFO = new VpnInfo[0];
-
private long mElapsedRealtime;
private HandlerThread mObserverHandlerThread;
@@ -248,8 +244,7 @@
NetworkStats uidSnapshot = null;
mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
- VPN_INFO, TEST_START);
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
waitForObserverToIdle();
}
@@ -272,15 +267,13 @@
.addIfaceValues(TEST_IFACE, BASE_BYTES, 8L, BASE_BYTES, 16L);
NetworkStats uidSnapshot = null;
mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
- VPN_INFO, TEST_START);
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
// Delta
xtSnapshot = new NetworkStats(TEST_START, 1 /* initialSize */)
.addIfaceValues(TEST_IFACE, BASE_BYTES + 1024L, 10L, BASE_BYTES + 2048L, 20L);
mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
- VPN_INFO, TEST_START);
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
waitForObserverToIdle();
}
@@ -304,16 +297,14 @@
.addIfaceValues(TEST_IFACE, BASE_BYTES, 8L, BASE_BYTES, 16L);
NetworkStats uidSnapshot = null;
mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
- VPN_INFO, TEST_START);
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
// Delta
xtSnapshot = new NetworkStats(TEST_START + MINUTE_IN_MILLIS, 1 /* initialSize */)
.addIfaceValues(TEST_IFACE, BASE_BYTES + THRESHOLD_BYTES, 12L,
BASE_BYTES + THRESHOLD_BYTES, 22L);
mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
- VPN_INFO, TEST_START);
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
waitForObserverToIdle();
assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.lastMessageType);
}
@@ -338,8 +329,7 @@
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
- VPN_INFO, TEST_START);
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
// Delta
uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
@@ -347,8 +337,7 @@
DEFAULT_NETWORK_NO, BASE_BYTES + THRESHOLD_BYTES, 2L,
BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
- VPN_INFO, TEST_START);
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
waitForObserverToIdle();
assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.lastMessageType);
}
@@ -373,8 +362,7 @@
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_NO, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
- VPN_INFO, TEST_START);
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
// Delta
uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
@@ -382,8 +370,7 @@
DEFAULT_NETWORK_NO, BASE_BYTES + THRESHOLD_BYTES, 2L,
BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
- VPN_INFO, TEST_START);
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
waitForObserverToIdle();
}
@@ -407,8 +394,7 @@
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
DEFAULT_NETWORK_YES, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
- VPN_INFO, TEST_START);
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
// Delta
uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
@@ -416,8 +402,7 @@
DEFAULT_NETWORK_YES, BASE_BYTES + THRESHOLD_BYTES, 2L,
BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
- VPN_INFO, TEST_START);
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
waitForObserverToIdle();
assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.lastMessageType);
}
@@ -442,8 +427,7 @@
.addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO,
ROAMING_NO, DEFAULT_NETWORK_YES, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
- VPN_INFO, TEST_START);
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
// Delta
uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
@@ -451,13 +435,12 @@
ROAMING_NO, DEFAULT_NETWORK_NO, BASE_BYTES + THRESHOLD_BYTES, 2L,
BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
- VPN_INFO, TEST_START);
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
waitForObserverToIdle();
}
private void waitForObserverToIdle() {
- waitForIdleHandler(mObserverHandlerThread, WAIT_TIMEOUT_MS);
- waitForIdleHandler(mHandler, WAIT_TIMEOUT_MS);
+ HandlerUtilsKt.waitForIdle(mObserverHandlerThread, WAIT_TIMEOUT_MS);
+ HandlerUtilsKt.waitForIdle(mHandler, WAIT_TIMEOUT_MS);
}
}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index e35c34a..1d29a82 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -23,7 +23,6 @@
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.ConnectivityManager.TYPE_WIMAX;
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
-import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
import static android.net.NetworkStats.IFACE_ALL;
import static android.net.NetworkStats.INTERFACES_ALL;
@@ -38,11 +37,11 @@
import static android.net.NetworkStats.SET_FOREGROUND;
import static android.net.NetworkStats.STATS_PER_IFACE;
import static android.net.NetworkStats.STATS_PER_UID;
+import static android.net.NetworkStats.TAG_ALL;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
import static android.net.NetworkStatsHistory.FIELD_ALL;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
-import static android.net.NetworkTemplate.buildTemplateMobileWildcard;
import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
import static android.net.TrafficStats.MB_IN_BYTES;
import static android.net.TrafficStats.UID_REMOVED;
@@ -52,17 +51,14 @@
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
-import static com.android.internal.util.TestUtils.waitForIdleHandler;
import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -105,6 +101,7 @@
import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.server.net.NetworkStatsService.NetworkStatsSettings;
import com.android.server.net.NetworkStatsService.NetworkStatsSettings.Config;
+import com.android.testutils.HandlerUtilsKt;
import libcore.io.IoUtils;
@@ -130,13 +127,9 @@
*/
@RunWith(AndroidJUnit4.class)
@SmallTest
-public class NetworkStatsServiceTest {
+public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
private static final String TAG = "NetworkStatsServiceTest";
- private static final String TEST_IFACE = "test0";
- private static final String TEST_IFACE2 = "test1";
- private static final String TUN_IFACE = "test_nss_tun0";
-
private static final long TEST_START = 1194220800000L;
private static final String IMSI_1 = "310004";
@@ -147,11 +140,6 @@
private static NetworkTemplate sTemplateImsi1 = buildTemplateMobileAll(IMSI_1);
private static NetworkTemplate sTemplateImsi2 = buildTemplateMobileAll(IMSI_2);
- private static final int UID_RED = 1001;
- private static final int UID_BLUE = 1002;
- private static final int UID_GREEN = 1003;
- private static final int UID_VPN = 1004;
-
private static final Network WIFI_NETWORK = new Network(100);
private static final Network MOBILE_NETWORK = new Network(101);
private static final Network VPN_NETWORK = new Network(102);
@@ -168,6 +156,7 @@
private File mStatsDir;
private @Mock INetworkManagementService mNetManager;
+ private @Mock NetworkStatsFactory mStatsFactory;
private @Mock NetworkStatsSettings mSettings;
private @Mock IBinder mBinder;
private @Mock AlarmManager mAlarmManager;
@@ -203,8 +192,8 @@
mService = new NetworkStatsService(
mServiceContext, mNetManager, mAlarmManager, wakeLock, mClock,
- TelephonyManager.getDefault(), mSettings, new NetworkStatsObservers(),
- mStatsDir, getBaseDir(mStatsDir));
+ TelephonyManager.getDefault(), mSettings, mStatsFactory,
+ new NetworkStatsObservers(), mStatsDir, getBaseDir(mStatsDir));
mHandlerThread = new HandlerThread("HandlerThread");
mHandlerThread.start();
Handler.Callback callback = new NetworkStatsService.HandlerCallback(mService);
@@ -217,12 +206,9 @@
expectNetworkStatsUidDetail(buildEmptyStats());
expectSystemReady();
- assertNull(mService.getTunAdjustedStats());
mService.systemReady();
- // Verify that system ready fetches realtime stats and initializes tun adjusted stats.
- verify(mNetManager).getNetworkStatsUidDetail(UID_ALL, INTERFACES_ALL);
- assertNotNull("failed to initialize TUN adjusted stats", mService.getTunAdjustedStats());
- assertEquals(0, mService.getTunAdjustedStats().size());
+ // Verify that system ready fetches realtime stats
+ verify(mStatsFactory).readNetworkStatsDetail(UID_ALL, INTERFACES_ALL, TAG_ALL);
mSession = mService.openSession();
assertNotNull("openSession() failed", mSession);
@@ -256,9 +242,8 @@
NetworkState[] states = new NetworkState[] {buildWifiState()};
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- expectBandwidthControlCheck();
- mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states));
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
// verify service has empty history for wifi
assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
@@ -300,9 +285,8 @@
NetworkState[] states = new NetworkState[] {buildWifiState()};
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- expectBandwidthControlCheck();
- mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states));
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
// verify service has empty history for wifi
assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
@@ -374,10 +358,8 @@
NetworkState[] states = new NetworkState[] {buildWifiState()};
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- expectBandwidthControlCheck();
- mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states));
-
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
// modify some number on wifi, and trigger poll event
incrementCurrentTime(2 * HOUR_IN_MILLIS);
@@ -416,10 +398,8 @@
NetworkState[] states = new NetworkState[] {buildMobile3gState(IMSI_1)};
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- expectBandwidthControlCheck();
- mService.forceUpdateIfaces(NETWORKS_MOBILE, new VpnInfo[0], states, getActiveIface(states));
-
+ mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
// create some traffic on first network
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -452,9 +432,8 @@
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L)
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
.addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L));
- expectBandwidthControlCheck();
- mService.forceUpdateIfaces(NETWORKS_MOBILE, new VpnInfo[0], states, getActiveIface(states));
+ mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
forcePollAndWaitForIdle();
@@ -492,10 +471,8 @@
NetworkState[] states = new NetworkState[] {buildWifiState()};
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- expectBandwidthControlCheck();
- mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states));
-
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
// create some traffic
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -551,10 +528,8 @@
NetworkState[] states = new NetworkState[] {buildMobile3gState(IMSI_1)};
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- expectBandwidthControlCheck();
- mService.forceUpdateIfaces(NETWORKS_MOBILE, new VpnInfo[0], states, getActiveIface(states));
-
+ mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
// create some traffic
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -579,9 +554,8 @@
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L)
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L));
- expectBandwidthControlCheck();
- mService.forceUpdateIfaces(NETWORKS_MOBILE, new VpnInfo[0], states, getActiveIface(states));
+ mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
forcePollAndWaitForIdle();
@@ -609,10 +583,8 @@
NetworkState[] states = new NetworkState[] {buildWifiState()};
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- expectBandwidthControlCheck();
- mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states));
-
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
// create some traffic for two apps
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -668,9 +640,8 @@
NetworkState[] states = new NetworkState[] {buildWifiState()};
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- expectBandwidthControlCheck();
- mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states));
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
NetworkStats.Entry entry1 = new NetworkStats.Entry(
TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L);
@@ -712,9 +683,8 @@
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- expectBandwidthControlCheck();
- mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states));
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
NetworkStats.Entry uidStats = new NetworkStats.Entry(
TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L);
@@ -726,10 +696,13 @@
"otherif", UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L);
final String[] ifaceFilter = new String[] { TEST_IFACE };
+ final String[] augmentedIfaceFilter = new String[] { stackedIface, TEST_IFACE };
incrementCurrentTime(HOUR_IN_MILLIS);
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
- when(mNetManager.getNetworkStatsUidDetail(eq(UID_ALL), any()))
+ when(mStatsFactory.augmentWithStackedInterfaces(eq(ifaceFilter)))
+ .thenReturn(augmentedIfaceFilter);
+ when(mStatsFactory.readNetworkStatsDetail(eq(UID_ALL), any(), eq(TAG_ALL)))
.thenReturn(new NetworkStats(getElapsedRealtime(), 1)
.addValues(uidStats));
when(mNetManager.getNetworkStatsTethering(STATS_PER_UID))
@@ -739,11 +712,17 @@
NetworkStats stats = mService.getDetailedUidStats(ifaceFilter);
- // mNetManager#getNetworkStatsUidDetail(UID_ALL, INTERFACES_ALL) has following invocations:
+ // mStatsFactory#readNetworkStatsDetail() has the following invocations:
// 1) NetworkStatsService#systemReady from #setUp.
// 2) mService#forceUpdateIfaces in the test above.
- // 3) Finally, mService#getDetailedUidStats.
- verify(mNetManager, times(3)).getNetworkStatsUidDetail(UID_ALL, INTERFACES_ALL);
+ //
+ // Additionally, we should have one call from the above call to mService#getDetailedUidStats
+ // with the augmented ifaceFilter.
+ verify(mStatsFactory, times(2)).readNetworkStatsDetail(UID_ALL, INTERFACES_ALL, TAG_ALL);
+ verify(mStatsFactory, times(1)).readNetworkStatsDetail(
+ eq(UID_ALL),
+ eq(augmentedIfaceFilter),
+ eq(TAG_ALL));
assertTrue(ArrayUtils.contains(stats.getUniqueIfaces(), TEST_IFACE));
assertTrue(ArrayUtils.contains(stats.getUniqueIfaces(), stackedIface));
assertEquals(2, stats.size());
@@ -758,10 +737,8 @@
NetworkState[] states = new NetworkState[] {buildWifiState()};
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- expectBandwidthControlCheck();
- mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states));
-
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
// create some initial traffic
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -816,10 +793,8 @@
NetworkState[] states = new NetworkState[] {buildWifiState(true /* isMetered */)};
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- expectBandwidthControlCheck();
- mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states));
-
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
// create some initial traffic
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -857,10 +832,8 @@
new NetworkState[] {buildMobile3gState(IMSI_1, true /* isRoaming */)};
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- expectBandwidthControlCheck();
- mService.forceUpdateIfaces(NETWORKS_MOBILE, new VpnInfo[0], states, getActiveIface(states));
-
+ mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
// Create some traffic
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -896,10 +869,8 @@
NetworkState[] states = new NetworkState[] {buildMobile3gState(IMSI_1)};
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- expectBandwidthControlCheck();
- mService.forceUpdateIfaces(NETWORKS_MOBILE, new VpnInfo[0], states, getActiveIface(states));
-
+ mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]);
// create some tethering traffic
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -931,369 +902,6 @@
}
@Test
- public void vpnWithOneUnderlyingIface() throws Exception {
- // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE).
- expectDefaultSettings();
- NetworkState[] networkStates = new NetworkState[] {buildWifiState(), buildVpnState()};
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
- expectNetworkStatsUidDetail(buildEmptyStats());
- expectBandwidthControlCheck();
-
- mService.forceUpdateIfaces(
- new Network[] {WIFI_NETWORK, VPN_NETWORK},
- vpnInfos,
- networkStates,
- getActiveIface(networkStates));
- // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
- // overhead per packet):
- // 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
- // 500 bytes (50 packets) were sent/received by UID_BLUE over VPN.
- // VPN sent/received 1650 bytes (150 packets) over WiFi.
- // Of 1650 bytes over WiFi, expect 1000 bytes attributed to UID_RED, 500 bytes attributed to
- // UID_BLUE, and 150 bytes attributed to UID_VPN for both rx/tx traffic.
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
- .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 1L)
- .addValues(TUN_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 500L, 50L, 500L, 50L, 1L)
- // VPN received 1650 bytes over WiFi in background (SET_DEFAULT).
- .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 1650L, 150L, 0L, 0L, 1L)
- // VPN sent 1650 bytes over WiFi in foreground (SET_FOREGROUND).
- .addValues(TEST_IFACE, UID_VPN, SET_FOREGROUND, TAG_NONE, 0L, 0L, 1650L, 150L, 1L));
-
- forcePollAndWaitForIdle();
-
- assertUidTotal(sTemplateWifi, UID_RED, 1000L, 100L, 1000L, 100L, 1);
- assertUidTotal(sTemplateWifi, UID_BLUE, 500L, 50L, 500L, 50L, 1);
- assertUidTotal(sTemplateWifi, UID_VPN, 150L, 0L, 150L, 0L, 2);
- }
-
- @Test
- public void vpnWithOneUnderlyingIface_withCompression() throws Exception {
- // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE).
- expectDefaultSettings();
- NetworkState[] networkStates = new NetworkState[] {buildWifiState(), buildVpnState()};
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
- expectNetworkStatsUidDetail(buildEmptyStats());
- expectBandwidthControlCheck();
-
- mService.forceUpdateIfaces(
- new Network[] {WIFI_NETWORK, VPN_NETWORK},
- vpnInfos,
- networkStates,
- getActiveIface(networkStates));
- // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
- // overhead per packet):
- // 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
- // 3000 bytes (300 packets) were sent/received by UID_BLUE over VPN.
- // VPN sent/received 1000 bytes (100 packets) over WiFi.
- // Of 1000 bytes over WiFi, expect 250 bytes attributed UID_RED and 750 bytes to UID_BLUE,
- // with nothing attributed to UID_VPN for both rx/tx traffic.
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
- .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 1L)
- .addValues(TUN_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 3000L, 300L, 3000L, 300L, 1L)
- .addValues(
- TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 0L));
-
- forcePollAndWaitForIdle();
-
- assertUidTotal(sTemplateWifi, UID_RED, 250L, 25L, 250L, 25L, 0);
- assertUidTotal(sTemplateWifi, UID_BLUE, 750L, 75L, 750L, 75L, 0);
- assertUidTotal(sTemplateWifi, UID_VPN, 0L, 0L, 0L, 0L, 0);
- }
-
- @Test
- public void vpnWithTwoUnderlyingIfaces_packetDuplication() throws Exception {
- // WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and
- // Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set.
- // Additionally, VPN is duplicating traffic across both WiFi and Cell.
- expectDefaultSettings();
- NetworkState[] networkStates =
- new NetworkState[] {
- buildWifiState(), buildMobile4gState(TEST_IFACE2), buildVpnState()
- };
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
- expectNetworkStatsUidDetail(buildEmptyStats());
- expectBandwidthControlCheck();
-
- mService.forceUpdateIfaces(
- new Network[] {WIFI_NETWORK, VPN_NETWORK},
- vpnInfos,
- networkStates,
- getActiveIface(networkStates));
- // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
- // overhead per packet):
- // 1000 bytes (100 packets) were sent/received by UID_RED and UID_BLUE over VPN.
- // VPN sent/received 4400 bytes (400 packets) over both WiFi and Cell (8800 bytes in total).
- // Of 8800 bytes over WiFi/Cell, expect:
- // - 500 bytes rx/tx each over WiFi/Cell attributed to both UID_RED and UID_BLUE.
- // - 1200 bytes rx/tx each over WiFi/Cell for VPN_UID.
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 4)
- .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 2L)
- .addValues(TUN_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 2L)
- .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 2200L, 200L, 2200L, 200L, 2L)
- .addValues(
- TEST_IFACE2, UID_VPN, SET_DEFAULT, TAG_NONE, 2200L, 200L, 2200L, 200L, 2L));
-
- forcePollAndWaitForIdle();
-
- assertUidTotal(sTemplateWifi, UID_RED, 500L, 50L, 500L, 50L, 1);
- assertUidTotal(sTemplateWifi, UID_BLUE, 500L, 50L, 500L, 50L, 1);
- assertUidTotal(sTemplateWifi, UID_VPN, 1200L, 100L, 1200L, 100L, 2);
-
- assertUidTotal(buildTemplateMobileWildcard(), UID_RED, 500L, 50L, 500L, 50L, 1);
- assertUidTotal(buildTemplateMobileWildcard(), UID_BLUE, 500L, 50L, 500L, 50L, 1);
- assertUidTotal(buildTemplateMobileWildcard(), UID_VPN, 1200L, 100L, 1200L, 100L, 2);
- }
-
- @Test
- public void vpnWithTwoUnderlyingIfaces_splitTraffic() throws Exception {
- // WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and
- // Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set.
- // Additionally, VPN is arbitrarily splitting traffic across WiFi and Cell.
- expectDefaultSettings();
- NetworkState[] networkStates =
- new NetworkState[] {
- buildWifiState(), buildMobile4gState(TEST_IFACE2), buildVpnState()
- };
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
- expectNetworkStatsUidDetail(buildEmptyStats());
- expectBandwidthControlCheck();
-
- mService.forceUpdateIfaces(
- new Network[] {WIFI_NETWORK, VPN_NETWORK},
- vpnInfos,
- networkStates,
- getActiveIface(networkStates));
- // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
- // overhead per packet):
- // 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
- // VPN sent/received 660 bytes (60 packets) over WiFi and 440 bytes (40 packets) over Cell.
- // For UID_RED, expect 600 bytes attributed over WiFi and 400 bytes over Cell for both
- // rx/tx.
- // For UID_VPN, expect 60 bytes attributed over WiFi and 40 bytes over Cell for both rx/tx.
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
- .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 2L)
- .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 660L, 60L, 660L, 60L, 1L)
- .addValues(TEST_IFACE2, UID_VPN, SET_DEFAULT, TAG_NONE, 440L, 40L, 440L, 40L, 1L));
-
- forcePollAndWaitForIdle();
-
- assertUidTotal(sTemplateWifi, UID_RED, 600L, 60L, 600L, 60L, 1);
- assertUidTotal(sTemplateWifi, UID_VPN, 60L, 0L, 60L, 0L, 1);
-
- assertUidTotal(buildTemplateMobileWildcard(), UID_RED, 400L, 40L, 400L, 40L, 1);
- assertUidTotal(buildTemplateMobileWildcard(), UID_VPN, 40L, 0L, 40L, 0L, 1);
- }
-
- @Test
- public void vpnWithTwoUnderlyingIfaces_splitTrafficWithCompression() throws Exception {
- // WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and
- // Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set.
- // Additionally, VPN is arbitrarily splitting compressed traffic across WiFi and Cell.
- expectDefaultSettings();
- NetworkState[] networkStates =
- new NetworkState[] {
- buildWifiState(), buildMobile4gState(TEST_IFACE2), buildVpnState()
- };
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
- expectNetworkStatsUidDetail(buildEmptyStats());
- expectBandwidthControlCheck();
-
- mService.forceUpdateIfaces(
- new Network[] {WIFI_NETWORK, VPN_NETWORK},
- vpnInfos,
- networkStates,
- getActiveIface(networkStates));
- // create some traffic (assume 10 bytes of MTU for VPN interface:
- // 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
- // VPN sent/received 600 bytes (60 packets) over WiFi and 200 bytes (20 packets) over Cell.
- // For UID_RED, expect 600 bytes attributed over WiFi and 200 bytes over Cell for both
- // rx/tx.
- // UID_VPN gets nothing attributed to it (avoiding negative stats).
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 4)
- .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 1L)
- .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 600L, 60L, 600L, 60L, 0L)
- .addValues(TEST_IFACE2, UID_VPN, SET_DEFAULT, TAG_NONE, 200L, 20L, 200L, 20L, 0L));
-
- forcePollAndWaitForIdle();
-
- assertUidTotal(sTemplateWifi, UID_RED, 600L, 60L, 600L, 60L, 0);
- assertUidTotal(sTemplateWifi, UID_VPN, 0L, 0L, 0L, 0L, 0);
-
- assertUidTotal(buildTemplateMobileWildcard(), UID_RED, 200L, 20L, 200L, 20L, 0);
- assertUidTotal(buildTemplateMobileWildcard(), UID_VPN, 0L, 0L, 0L, 0L, 0);
- }
-
- @Test
- public void vpnWithIncorrectUnderlyingIface() throws Exception {
- // WiFi and Cell networks are connected and VPN is using Cell (which has TEST_IFACE2),
- // but has declared only WiFi (TEST_IFACE) in its underlying network set.
- expectDefaultSettings();
- NetworkState[] networkStates =
- new NetworkState[] {
- buildWifiState(), buildMobile4gState(TEST_IFACE2), buildVpnState()
- };
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
- expectNetworkStatsUidDetail(buildEmptyStats());
- expectBandwidthControlCheck();
-
- mService.forceUpdateIfaces(
- new Network[] {WIFI_NETWORK, VPN_NETWORK},
- vpnInfos,
- networkStates,
- getActiveIface(networkStates));
- // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
- // overhead per packet):
- // 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
- // VPN sent/received 1100 bytes (100 packets) over Cell.
- // Of 1100 bytes over Cell, expect all of it attributed to UID_VPN for both rx/tx traffic.
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2)
- .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 1L)
- .addValues(
- TEST_IFACE2, UID_VPN, SET_DEFAULT, TAG_NONE, 1100L, 100L, 1100L, 100L, 1L));
-
- forcePollAndWaitForIdle();
-
- assertUidTotal(sTemplateWifi, UID_RED, 0L, 0L, 0L, 0L, 0);
- assertUidTotal(sTemplateWifi, UID_VPN, 0L, 0L, 0L, 0L, 0);
- assertUidTotal(buildTemplateMobileWildcard(), UID_RED, 0L, 0L, 0L, 0L, 0);
- assertUidTotal(buildTemplateMobileWildcard(), UID_VPN, 1100L, 100L, 1100L, 100L, 1);
- }
-
- @Test
- public void recordSnapshot_migratesTunTrafficAndUpdatesTunAdjustedStats() throws Exception {
- assertEquals(0, mService.getTunAdjustedStats().size());
- // VPN using WiFi (TEST_IFACE).
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
- expectBandwidthControlCheck();
- // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
- // overhead per packet):
- // 1000 bytes (100 packets) were downloaded by UID_RED over VPN.
- // VPN received 1100 bytes (100 packets) over WiFi.
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2)
- .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 1100L, 100L, 0L, 0L, 0L));
-
- // this should lead to NSS#recordSnapshotLocked
- mService.forceUpdateIfaces(
- new Network[0], vpnInfos, new NetworkState[0], null /* activeIface */);
-
- // Verify TUN adjusted stats have traffic migrated correctly.
- // Of 1100 bytes VPN received over WiFi, expect 1000 bytes attributed to UID_RED and 100
- // bytes attributed to UID_VPN.
- NetworkStats tunAdjStats = mService.getTunAdjustedStats();
- assertValues(
- tunAdjStats, TEST_IFACE, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, 1000L, 100L, 0L, 0L, 0);
- assertValues(
- tunAdjStats, TEST_IFACE, UID_VPN, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, 100L, 0L, 0L, 0L, 0);
- }
-
- @Test
- public void getDetailedUidStats_migratesTunTrafficAndUpdatesTunAdjustedStats()
- throws Exception {
- assertEquals(0, mService.getTunAdjustedStats().size());
- // VPN using WiFi (TEST_IFACE).
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
- expectBandwidthControlCheck();
- mService.forceUpdateIfaces(
- new Network[0], vpnInfos, new NetworkState[0], null /* activeIface */);
- // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
- // overhead per packet):
- // 1000 bytes (100 packets) were downloaded by UID_RED over VPN.
- // VPN received 1100 bytes (100 packets) over WiFi.
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2)
- .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 1100L, 100L, 0L, 0L, 0L));
-
- mService.getDetailedUidStats(INTERFACES_ALL);
-
- // Verify internally maintained TUN adjusted stats
- NetworkStats tunAdjStats = mService.getTunAdjustedStats();
- // Verify stats for TEST_IFACE (WiFi):
- // Of 1100 bytes VPN received over WiFi, expect 1000 bytes attributed to UID_RED and 100
- // bytes attributed to UID_VPN.
- assertValues(
- tunAdjStats, TEST_IFACE, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, 1000L, 100L, 0L, 0L, 0);
- assertValues(
- tunAdjStats, TEST_IFACE, UID_VPN, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, 100L, 0L, 0L, 0L, 0);
- // Verify stats for TUN_IFACE; only UID_RED should have usage on it.
- assertValues(
- tunAdjStats, TUN_IFACE, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, 1000L, 100L, 0L, 0L, 0);
- assertValues(
- tunAdjStats, TUN_IFACE, UID_VPN, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, 0L, 0L, 0L, 0L, 0);
-
- // lets assume that since last time, VPN received another 1100 bytes (same assumptions as
- // before i.e. UID_RED downloaded another 1000 bytes).
- incrementCurrentTime(HOUR_IN_MILLIS);
- // Note - NetworkStatsFactory returns counters that are monotonically increasing.
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2)
- .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 2000L, 200L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 2200L, 200L, 0L, 0L, 0L));
-
- mService.getDetailedUidStats(INTERFACES_ALL);
-
- tunAdjStats = mService.getTunAdjustedStats();
- // verify TEST_IFACE stats:
- assertValues(
- tunAdjStats, TEST_IFACE, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, 2000L, 200L, 0L, 0L, 0);
- assertValues(
- tunAdjStats, TEST_IFACE, UID_VPN, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, 200L, 0L, 0L, 0L, 0);
- // verify TUN_IFACE stats:
- assertValues(
- tunAdjStats, TUN_IFACE, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, 2000L, 200L, 0L, 0L, 0);
- assertValues(
- tunAdjStats, TUN_IFACE, UID_VPN, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, 0L, 0L, 0L, 0L, 0);
- }
-
- @Test
- public void getDetailedUidStats_returnsCorrectStatsWithVpnRunning() throws Exception {
- // VPN using WiFi (TEST_IFACE).
- VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
- expectBandwidthControlCheck();
- mService.forceUpdateIfaces(
- new Network[0], vpnInfos, new NetworkState[0], null /* activeIface */);
- // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
- // overhead per packet):
- // 1000 bytes (100 packets) were downloaded by UID_RED over VPN.
- // VPN received 1100 bytes (100 packets) over WiFi.
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2)
- .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 1100L, 100L, 0L, 0L, 0L));
-
- // Query realtime stats for TEST_IFACE.
- NetworkStats queriedStats =
- mService.getDetailedUidStats(new String[] {TEST_IFACE});
-
- assertEquals(HOUR_IN_MILLIS, queriedStats.getElapsedRealtime());
- // verify that returned stats are only for TEST_IFACE and VPN traffic is migrated correctly.
- assertEquals(new String[] {TEST_IFACE}, queriedStats.getUniqueIfaces());
- assertValues(
- queriedStats, TEST_IFACE, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, 1000L, 100L, 0L, 0L, 0);
- assertValues(
- queriedStats, TEST_IFACE, UID_VPN, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, 100L, 0L, 0L, 0L, 0);
- }
-
- @Test
public void testRegisterUsageCallback() throws Exception {
// pretend that wifi network comes online; service should ask about full
// network state, and poll any existing interfaces before updating.
@@ -1301,9 +909,8 @@
NetworkState[] states = new NetworkState[] {buildWifiState()};
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
- expectBandwidthControlCheck();
- mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states));
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
// verify service has empty history for wifi
assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
@@ -1321,8 +928,6 @@
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
-
-
// Register and verify request and that binder was called
DataUsageRequest request =
mService.registerUsageCallback(mServiceContext.getOpPackageName(), inputRequest,
@@ -1334,14 +939,11 @@
// Send dummy message to make sure that any previous message has been handled
mHandler.sendMessage(mHandler.obtainMessage(-1));
- waitForIdleHandler(mHandler, WAIT_TIMEOUT);
-
-
+ HandlerUtilsKt.waitForIdle(mHandler, WAIT_TIMEOUT);
// Make sure that the caller binder gets connected
verify(mBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
-
// modify some number on wifi, and trigger poll event
// not enough traffic to call data usage callback
incrementCurrentTime(HOUR_IN_MILLIS);
@@ -1447,7 +1049,6 @@
private void expectSystemReady() throws Exception {
expectNetworkStatsSummary(buildEmptyStats());
- expectBandwidthControlCheck();
}
private String getActiveIface(NetworkState... states) throws Exception {
@@ -1469,11 +1070,11 @@
}
private void expectNetworkStatsSummaryDev(NetworkStats summary) throws Exception {
- when(mNetManager.getNetworkStatsSummaryDev()).thenReturn(summary);
+ when(mStatsFactory.readNetworkStatsSummaryDev()).thenReturn(summary);
}
private void expectNetworkStatsSummaryXt(NetworkStats summary) throws Exception {
- when(mNetManager.getNetworkStatsSummaryXt()).thenReturn(summary);
+ when(mStatsFactory.readNetworkStatsSummaryXt()).thenReturn(summary);
}
private void expectNetworkStatsTethering(int how, NetworkStats stats)
@@ -1487,7 +1088,8 @@
private void expectNetworkStatsUidDetail(NetworkStats detail, NetworkStats tetherStats)
throws Exception {
- when(mNetManager.getNetworkStatsUidDetail(UID_ALL, INTERFACES_ALL)).thenReturn(detail);
+ when(mStatsFactory.readNetworkStatsDetail(UID_ALL, INTERFACES_ALL, TAG_ALL))
+ .thenReturn(detail);
// also include tethering details, since they are folded into UID
when(mNetManager.getNetworkStatsTethering(STATS_PER_UID)).thenReturn(tetherStats);
@@ -1515,10 +1117,6 @@
when(mSettings.getUidTagPersistBytes(anyLong())).thenReturn(MB_IN_BYTES);
}
- private void expectBandwidthControlCheck() throws Exception {
- when(mNetManager.isBandwidthControlEnabled()).thenReturn(true);
- }
-
private void assertStatsFilesExist(boolean exist) {
final File basePath = new File(mStatsDir, "netstats");
if (exist) {
@@ -1528,59 +1126,6 @@
}
}
- private static void assertValues(NetworkStats stats, String iface, int uid, int set,
- int tag, int metered, int roaming, int defaultNetwork, long rxBytes, long rxPackets,
- long txBytes, long txPackets, int operations) {
- final NetworkStats.Entry entry = new NetworkStats.Entry();
- final int[] sets;
- if (set == SET_ALL) {
- sets = new int[] { SET_ALL, SET_DEFAULT, SET_FOREGROUND };
- } else {
- sets = new int[] { set };
- }
-
- final int[] roamings;
- if (roaming == ROAMING_ALL) {
- roamings = new int[] { ROAMING_ALL, ROAMING_YES, ROAMING_NO };
- } else {
- roamings = new int[] { roaming };
- }
-
- final int[] meterings;
- if (metered == METERED_ALL) {
- meterings = new int[] { METERED_ALL, METERED_YES, METERED_NO };
- } else {
- meterings = new int[] { metered };
- }
-
- final int[] defaultNetworks;
- if (defaultNetwork == DEFAULT_NETWORK_ALL) {
- defaultNetworks = new int[] { DEFAULT_NETWORK_ALL, DEFAULT_NETWORK_YES,
- DEFAULT_NETWORK_NO };
- } else {
- defaultNetworks = new int[] { defaultNetwork };
- }
-
- for (int s : sets) {
- for (int r : roamings) {
- for (int m : meterings) {
- for (int d : defaultNetworks) {
- final int i = stats.findIndex(iface, uid, s, tag, m, r, d);
- if (i != -1) {
- entry.add(stats.getValues(i, null));
- }
- }
- }
- }
- }
-
- assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
- assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
- assertEquals("unexpected txBytes", txBytes, entry.txBytes);
- assertEquals("unexpected txPackets", txPackets, entry.txPackets);
- assertEquals("unexpected operations", operations, entry.operations);
- }
-
private static void assertValues(NetworkStatsHistory stats, long start, long end, long rxBytes,
long rxPackets, long txBytes, long txPackets, int operations) {
final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null);
@@ -1646,14 +1191,6 @@
return new NetworkState(info, prop, new NetworkCapabilities(), VPN_NETWORK, null, null);
}
- private static VpnInfo createVpnInfo(String[] underlyingIfaces) {
- VpnInfo info = new VpnInfo();
- info.ownerUid = UID_VPN;
- info.vpnIface = TUN_IFACE;
- info.underlyingIfaces = underlyingIfaces;
- return info;
- }
-
private long getElapsedRealtime() {
return mElapsedRealtime;
}
@@ -1674,7 +1211,7 @@
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
// Send dummy message to make sure that any previous message has been handled
mHandler.sendMessage(mHandler.obtainMessage(-1));
- waitForIdleHandler(mHandler, WAIT_TIMEOUT);
+ HandlerUtilsKt.waitForIdle(mHandler, WAIT_TIMEOUT);
}
static class LatchedHandler extends Handler {
diff --git a/tests/net/res/raw/xt_qtaguid_vpn_incorrect_iface b/tests/net/res/raw/xt_qtaguid_vpn_incorrect_iface
new file mode 100644
index 0000000..fc92715
--- /dev/null
+++ b/tests/net/res/raw/xt_qtaguid_vpn_incorrect_iface
@@ -0,0 +1,3 @@
+idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
+2 test_nss_tun0 0x0 1001 0 1000 100 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
+3 test1 0x0 1004 0 1100 100 1100 100 0 0 0 0 0 0 0 0 0 0 0 0
\ No newline at end of file
diff --git a/tests/net/res/raw/xt_qtaguid_vpn_one_underlying b/tests/net/res/raw/xt_qtaguid_vpn_one_underlying
new file mode 100644
index 0000000..1ef1889
--- /dev/null
+++ b/tests/net/res/raw/xt_qtaguid_vpn_one_underlying
@@ -0,0 +1,5 @@
+idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
+2 test_nss_tun0 0x0 1001 0 2000 200 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
+3 test_nss_tun0 0x0 1002 0 1000 100 500 50 0 0 0 0 0 0 0 0 0 0 0 0
+4 test0 0x0 1004 0 3300 300 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+5 test0 0x0 1004 1 0 0 1650 150 0 0 0 0 0 0 0 0 0 0 0 0
\ No newline at end of file
diff --git a/tests/net/res/raw/xt_qtaguid_vpn_one_underlying_compression b/tests/net/res/raw/xt_qtaguid_vpn_one_underlying_compression
new file mode 100644
index 0000000..6d6bf55
--- /dev/null
+++ b/tests/net/res/raw/xt_qtaguid_vpn_one_underlying_compression
@@ -0,0 +1,4 @@
+idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
+2 test_nss_tun0 0x0 1001 0 1000 100 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
+3 test_nss_tun0 0x0 1002 0 3000 300 3000 300 0 0 0 0 0 0 0 0 0 0 0 0
+4 test0 0x0 1004 0 1000 100 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
\ No newline at end of file
diff --git a/tests/net/res/raw/xt_qtaguid_vpn_one_underlying_own_traffic b/tests/net/res/raw/xt_qtaguid_vpn_one_underlying_own_traffic
new file mode 100644
index 0000000..2c2e5d2
--- /dev/null
+++ b/tests/net/res/raw/xt_qtaguid_vpn_one_underlying_own_traffic
@@ -0,0 +1,6 @@
+idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
+2 test_nss_tun0 0x0 1001 0 2000 200 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
+3 test_nss_tun0 0x0 1002 0 1000 100 500 50 0 0 0 0 0 0 0 0 0 0 0 0
+4 test_nss_tun0 0x0 1004 0 5000 500 6000 600 0 0 0 0 0 0 0 0 0 0 0 0
+5 test0 0x0 1004 0 8800 800 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+6 test0 0x0 1004 1 0 0 8250 750 0 0 0 0 0 0 0 0 0 0 0 0
\ No newline at end of file
diff --git a/tests/net/res/raw/xt_qtaguid_vpn_rewrite_through_self b/tests/net/res/raw/xt_qtaguid_vpn_rewrite_through_self
new file mode 100644
index 0000000..afcdd71
--- /dev/null
+++ b/tests/net/res/raw/xt_qtaguid_vpn_rewrite_through_self
@@ -0,0 +1,6 @@
+idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
+2 test_nss_tun0 0x0 1001 0 2000 200 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
+3 test_nss_tun0 0x0 1002 0 1000 100 500 50 0 0 0 0 0 0 0 0 0 0 0 0
+4 test_nss_tun0 0x0 1004 0 0 0 1600 160 0 0 0 0 0 0 0 0 0 0 0 0
+5 test0 0x0 1004 1 0 0 1760 176 0 0 0 0 0 0 0 0 0 0 0 0
+6 test0 0x0 1004 0 3300 300 0 0 0 0 0 0 0 0 0 0 0 0 0 0
\ No newline at end of file
diff --git a/tests/net/res/raw/xt_qtaguid_vpn_two_underlying_duplication b/tests/net/res/raw/xt_qtaguid_vpn_two_underlying_duplication
new file mode 100644
index 0000000..d7c7eb9
--- /dev/null
+++ b/tests/net/res/raw/xt_qtaguid_vpn_two_underlying_duplication
@@ -0,0 +1,5 @@
+idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
+2 test_nss_tun0 0x0 1001 0 1000 100 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
+3 test_nss_tun0 0x0 1002 0 1000 100 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
+4 test0 0x0 1004 0 2200 200 2200 200 0 0 0 0 0 0 0 0 0 0 0 0
+5 test1 0x0 1004 0 2200 200 2200 200 0 0 0 0 0 0 0 0 0 0 0 0
\ No newline at end of file
diff --git a/tests/net/res/raw/xt_qtaguid_vpn_two_underlying_split b/tests/net/res/raw/xt_qtaguid_vpn_two_underlying_split
new file mode 100644
index 0000000..38a3dce
--- /dev/null
+++ b/tests/net/res/raw/xt_qtaguid_vpn_two_underlying_split
@@ -0,0 +1,4 @@
+idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
+2 test_nss_tun0 0x0 1001 0 500 50 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
+3 test0 0x0 1004 0 330 30 660 60 0 0 0 0 0 0 0 0 0 0 0 0
+4 test1 0x0 1004 0 220 20 440 40 0 0 0 0 0 0 0 0 0 0 0 0
\ No newline at end of file
diff --git a/tests/net/res/raw/xt_qtaguid_vpn_two_underlying_split_compression b/tests/net/res/raw/xt_qtaguid_vpn_two_underlying_split_compression
new file mode 100644
index 0000000..d35244b
--- /dev/null
+++ b/tests/net/res/raw/xt_qtaguid_vpn_two_underlying_split_compression
@@ -0,0 +1,4 @@
+idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
+2 test_nss_tun0 0x0 1001 0 1000 100 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
+3 test0 0x0 1004 0 600 60 600 60 0 0 0 0 0 0 0 0 0 0 0 0
+4 test1 0x0 1004 0 200 20 200 20 0 0 0 0 0 0 0 0 0 0 0 0
\ No newline at end of file
diff --git a/tests/net/res/raw/xt_qtaguid_vpn_with_clat b/tests/net/res/raw/xt_qtaguid_vpn_with_clat
new file mode 100644
index 0000000..0d893d5
--- /dev/null
+++ b/tests/net/res/raw/xt_qtaguid_vpn_with_clat
@@ -0,0 +1,8 @@
+idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
+2 test_nss_tun0 0x0 1001 0 2000 200 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
+3 test_nss_tun0 0x0 1002 0 1000 100 500 50 0 0 0 0 0 0 0 0 0 0 0 0
+4 v4-test0 0x0 1004 0 3300 300 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+5 v4-test0 0x0 1004 1 0 0 1650 150 0 0 0 0 0 0 0 0 0 0 0 0
+6 test0 0x0 0 0 9300 300 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+7 test0 0x0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+8 test0 0x0 1029 0 0 0 4650 150 0 0 0 0 0 0 0 0 0 0 0 0
\ No newline at end of file
diff --git a/tests/net/res/raw/xt_qtaguid_with_clat_simple b/tests/net/res/raw/xt_qtaguid_with_clat_simple
index 8c132e7..b37fae6 100644
--- a/tests/net/res/raw/xt_qtaguid_with_clat_simple
+++ b/tests/net/res/raw/xt_qtaguid_with_clat_simple
@@ -2,5 +2,4 @@
2 v4-wlan0 0x0 10060 0 42600 213 4100 41 42600 213 0 0 0 0 4100 41 0 0 0 0
3 v4-wlan0 0x0 10060 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
4 wlan0 0x0 0 0 46860 213 0 0 46860 213 0 0 0 0 0 0 0 0 0 0
-5 wlan0 0x0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-6 wlan0 0x0 1029 0 0 0 4920 41 0 0 0 0 0 0 4920 41 0 0 0 0
+5 wlan0 0x0 1029 0 0 0 4920 41 0 0 0 0 0 0 4920 41 0 0 0 0
diff --git a/tests/net/smoketest/Android.bp b/tests/net/smoketest/Android.bp
index ef1ad2c..84ae2b5 100644
--- a/tests/net/smoketest/Android.bp
+++ b/tests/net/smoketest/Android.bp
@@ -14,4 +14,9 @@
defaults: ["FrameworksNetTests-jni-defaults"],
srcs: ["java/SmokeTest.java"],
test_suites: ["device-tests"],
-}
+ static_libs: [
+ "androidx.test.rules",
+ "mockito-target-minus-junit4",
+ "services.core",
+ ],
+}
\ No newline at end of file