Merge "Check if network has partial connectivity" am: 2d3cc4577a am: 0ea87a4edb
am: 973a569390
Change-Id: Ib6c5ecc8238e1ac237eddcc00802fa5e7c0e24b9
diff --git a/core/java/android/net/CaptivePortal.java b/core/java/android/net/CaptivePortal.java
index 3ab35e1..f208724 100644
--- a/core/java/android/net/CaptivePortal.java
+++ b/core/java/android/net/CaptivePortal.java
@@ -61,7 +61,7 @@
out.writeStrongBinder(mBinder);
}
- public static final Parcelable.Creator<CaptivePortal> CREATOR
+ public static final @android.annotation.NonNull Parcelable.Creator<CaptivePortal> CREATOR
= new Parcelable.Creator<CaptivePortal>() {
@Override
public CaptivePortal createFromParcel(Parcel in) {
diff --git a/core/java/android/net/ConnectionInfo.java b/core/java/android/net/ConnectionInfo.java
index 58d0e05..4514a84 100644
--- a/core/java/android/net/ConnectionInfo.java
+++ b/core/java/android/net/ConnectionInfo.java
@@ -54,7 +54,7 @@
out.writeInt(remote.getPort());
}
- public static final Creator<ConnectionInfo> CREATOR = new Creator<ConnectionInfo>() {
+ public static final @android.annotation.NonNull Creator<ConnectionInfo> CREATOR = new Creator<ConnectionInfo>() {
public ConnectionInfo createFromParcel(Parcel in) {
int protocol = in.readInt();
InetAddress localAddress;
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 91fefa2..3f8410f 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -3158,11 +3158,11 @@
}
}
- /** {@hide} */
+ /** {@hide} - returns the factory serial number */
@UnsupportedAppUsage
- public void registerNetworkFactory(Messenger messenger, String name) {
+ public int registerNetworkFactory(Messenger messenger, String name) {
try {
- mService.registerNetworkFactory(messenger, name);
+ return mService.registerNetworkFactory(messenger, name);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3178,6 +3178,10 @@
}
}
+ // TODO : remove this method. It is a stopgap measure to help sheperding a number
+ // of dependent changes that would conflict throughout the automerger graph. Having this
+ // temporarily helps with the process of going through with all these dependent changes across
+ // the entire tree.
/**
* @hide
* Register a NetworkAgent with ConnectivityService.
@@ -3185,8 +3189,20 @@
*/
public int registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
NetworkCapabilities nc, int score, NetworkMisc misc) {
+ return registerNetworkAgent(messenger, ni, lp, nc, score, misc,
+ NetworkFactory.SerialNumber.NONE);
+ }
+
+ /**
+ * @hide
+ * Register a NetworkAgent with ConnectivityService.
+ * @return NetID corresponding to NetworkAgent.
+ */
+ public int registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
+ NetworkCapabilities nc, int score, NetworkMisc misc, int factorySerialNumber) {
try {
- return mService.registerNetworkAgent(messenger, ni, lp, nc, score, misc);
+ return mService.registerNetworkAgent(messenger, ni, lp, nc, score, misc,
+ factorySerialNumber);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3286,9 +3302,9 @@
/**
* Called if no network is found in the timeout time specified in
- * {@link #requestNetwork(NetworkRequest, NetworkCallback, int)} call. This callback is not
- * called for the version of {@link #requestNetwork(NetworkRequest, NetworkCallback)}
- * without timeout. When this callback is invoked the associated
+ * {@link #requestNetwork(NetworkRequest, NetworkCallback, int)} call or if the
+ * requested network request cannot be fulfilled (whether or not a timeout was
+ * specified). When this callback is invoked the associated
* {@link NetworkRequest} will have already been removed and released, as if
* {@link #unregisterNetworkCallback(NetworkCallback)} had been called.
*/
diff --git a/core/java/android/net/DhcpInfo.java b/core/java/android/net/DhcpInfo.java
index 788d7d9..98bab44 100644
--- a/core/java/android/net/DhcpInfo.java
+++ b/core/java/android/net/DhcpInfo.java
@@ -84,7 +84,7 @@
}
/** Implement the Parcelable interface {@hide} */
- public static final Creator<DhcpInfo> CREATOR =
+ public static final @android.annotation.NonNull Creator<DhcpInfo> CREATOR =
new Creator<DhcpInfo>() {
public DhcpInfo createFromParcel(Parcel in) {
DhcpInfo info = new DhcpInfo();
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 2df4e75..403b44d 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -150,14 +150,14 @@
void setAirplaneMode(boolean enable);
- void registerNetworkFactory(in Messenger messenger, in String name);
+ int registerNetworkFactory(in Messenger messenger, in String name);
boolean requestBandwidthUpdate(in Network network);
void unregisterNetworkFactory(in Messenger messenger);
int registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp,
- in NetworkCapabilities nc, int score, in NetworkMisc misc);
+ in NetworkCapabilities nc, int score, in NetworkMisc misc, in int factorySerialNumber);
NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities,
in Messenger messenger, int timeoutSec, in IBinder binder, int legacy);
diff --git a/core/java/android/net/IpConfiguration.java b/core/java/android/net/IpConfiguration.java
index 3319f33..2af82d7 100644
--- a/core/java/android/net/IpConfiguration.java
+++ b/core/java/android/net/IpConfiguration.java
@@ -189,7 +189,7 @@
}
/** Implement the Parcelable interface */
- public static final Creator<IpConfiguration> CREATOR =
+ public static final @android.annotation.NonNull Creator<IpConfiguration> CREATOR =
new Creator<IpConfiguration>() {
public IpConfiguration createFromParcel(Parcel in) {
IpConfiguration config = new IpConfiguration();
diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java
index 175263f..21bbd30 100644
--- a/core/java/android/net/IpPrefix.java
+++ b/core/java/android/net/IpPrefix.java
@@ -285,7 +285,7 @@
/**
* Implement the Parcelable interface.
*/
- public static final Creator<IpPrefix> CREATOR =
+ public static final @android.annotation.NonNull Creator<IpPrefix> CREATOR =
new Creator<IpPrefix>() {
public IpPrefix createFromParcel(Parcel in) {
byte[] address = in.createByteArray();
diff --git a/core/java/android/net/KeepalivePacketData.java b/core/java/android/net/KeepalivePacketData.java
index 18726f7..9b8b732 100644
--- a/core/java/android/net/KeepalivePacketData.java
+++ b/core/java/android/net/KeepalivePacketData.java
@@ -105,7 +105,7 @@
}
/** Parcelable Creator */
- public static final Parcelable.Creator<KeepalivePacketData> CREATOR =
+ public static final @android.annotation.NonNull Parcelable.Creator<KeepalivePacketData> CREATOR =
new Parcelable.Creator<KeepalivePacketData>() {
public KeepalivePacketData createFromParcel(Parcel in) {
return new KeepalivePacketData(in);
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index 8b01960..78a4e72 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -357,7 +357,7 @@
/**
* Implement the Parcelable interface.
*/
- public static final Creator<LinkAddress> CREATOR =
+ public static final @android.annotation.NonNull Creator<LinkAddress> CREATOR =
new Creator<LinkAddress>() {
public LinkAddress createFromParcel(Parcel in) {
InetAddress address = null;
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 42db0fd..b52b15e 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -1574,7 +1574,7 @@
/**
* Implement the Parcelable interface.
*/
- public static final Creator<LinkProperties> CREATOR =
+ public static final @android.annotation.NonNull Creator<LinkProperties> CREATOR =
new Creator<LinkProperties>() {
public LinkProperties createFromParcel(Parcel in) {
LinkProperties netProp = new LinkProperties();
diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java
index c2b7d2c..aa8e010 100644
--- a/core/java/android/net/MacAddress.java
+++ b/core/java/android/net/MacAddress.java
@@ -167,7 +167,7 @@
return 0;
}
- public static final Parcelable.Creator<MacAddress> CREATOR =
+ public static final @android.annotation.NonNull Parcelable.Creator<MacAddress> CREATOR =
new Parcelable.Creator<MacAddress>() {
public MacAddress createFromParcel(Parcel in) {
return new MacAddress(in.readLong());
@@ -400,6 +400,21 @@
}
/**
+ * Checks if this MAC Address matches the provided range.
+ *
+ * @param baseAddress MacAddress representing the base address to compare with.
+ * @param mask MacAddress representing the mask to use during comparison.
+ * @return true if this MAC Address matches the given range.
+ *
+ * @hide
+ */
+ public boolean matches(@NonNull MacAddress baseAddress, @NonNull MacAddress mask) {
+ Preconditions.checkNotNull(baseAddress);
+ Preconditions.checkNotNull(mask);
+ return (mAddr & mask.mAddr) == (baseAddress.mAddr & mask.mAddr);
+ }
+
+ /**
* Create a link-local Inet6Address from the MAC address. The EUI-48 MAC address is converted
* to an EUI-64 MAC address per RFC 4291. The resulting EUI-64 is used to construct a link-local
* IPv6 address per RFC 4862.
diff --git a/core/java/android/net/NattKeepalivePacketData.java b/core/java/android/net/NattKeepalivePacketData.java
index bdb246f..5c55a98 100644
--- a/core/java/android/net/NattKeepalivePacketData.java
+++ b/core/java/android/net/NattKeepalivePacketData.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2018 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.
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index e04b5fc..0fafdf7 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -470,7 +470,7 @@
dest.writeInt(netId);
}
- public static final Creator<Network> CREATOR =
+ public static final @android.annotation.NonNull Creator<Network> CREATOR =
new Creator<Network>() {
public Network createFromParcel(Parcel in) {
int netId = in.readInt();
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 7bef690..273f8cd 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -57,6 +57,7 @@
private static final long BW_REFRESH_MIN_WIN_MS = 500;
private boolean mPollLceScheduled = false;
private AtomicBoolean mPollLcePending = new AtomicBoolean(false);
+ public final int mFactorySerialNumber;
private static final int BASE = Protocol.BASE_NETWORK_AGENT;
@@ -212,16 +213,31 @@
*/
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
+ // the entire tree.
public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
NetworkCapabilities nc, LinkProperties lp, int score) {
- this(looper, context, logTag, ni, nc, lp, score, null);
+ this(looper, context, logTag, ni, nc, lp, score, null, NetworkFactory.SerialNumber.NONE);
+ }
+ public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
+ NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {
+ this(looper, context, logTag, ni, nc, lp, score, misc, NetworkFactory.SerialNumber.NONE);
}
public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
- NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {
+ NetworkCapabilities nc, LinkProperties lp, int score, int factorySerialNumber) {
+ this(looper, context, logTag, ni, nc, lp, score, null, factorySerialNumber);
+ }
+
+ public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
+ NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc,
+ int factorySerialNumber) {
super(looper);
LOG_TAG = logTag;
mContext = context;
+ mFactorySerialNumber = factorySerialNumber;
if (ni == null || nc == null || lp == null) {
throw new IllegalArgumentException();
}
@@ -230,7 +246,8 @@
ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
Context.CONNECTIVITY_SERVICE);
netId = cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni),
- new LinkProperties(lp), new NetworkCapabilities(nc), score, misc);
+ new LinkProperties(lp), new NetworkCapabilities(nc), score, misc,
+ factorySerialNumber);
}
@Override
@@ -475,7 +492,7 @@
}
/**
- * Requests that the network hardware stops sending keepalive packets.
+ * Requests that the network hardware send the specified packet at the specified interval.
*/
protected void stopSocketKeepalive(Message msg) {
onSocketKeepaliveEvent(msg.arg1, SocketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index e1cfe99..c57ae0c 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -1476,7 +1476,7 @@
dest.writeString(mSSID);
}
- public static final Creator<NetworkCapabilities> CREATOR =
+ public static final @android.annotation.NonNull Creator<NetworkCapabilities> CREATOR =
new Creator<NetworkCapabilities>() {
@Override
public NetworkCapabilities createFromParcel(Parcel in) {
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index 89d9961..cd83531 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -557,7 +557,7 @@
}
}
- public static final Creator<NetworkInfo> CREATOR = new Creator<NetworkInfo>() {
+ public static final @android.annotation.NonNull Creator<NetworkInfo> CREATOR = new Creator<NetworkInfo>() {
@Override
public NetworkInfo createFromParcel(Parcel in) {
int netType = in.readInt();
diff --git a/core/java/android/net/NetworkMisc.java b/core/java/android/net/NetworkMisc.java
index 6fb2390..9ba3bd9 100644
--- a/core/java/android/net/NetworkMisc.java
+++ b/core/java/android/net/NetworkMisc.java
@@ -106,7 +106,7 @@
out.writeInt(skip464xlat ? 1 : 0);
}
- public static final Creator<NetworkMisc> CREATOR = new Creator<NetworkMisc>() {
+ public static final @android.annotation.NonNull Creator<NetworkMisc> CREATOR = new Creator<NetworkMisc>() {
@Override
public NetworkMisc createFromParcel(Parcel in) {
NetworkMisc networkMisc = new NetworkMisc();
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 9508217..dcb027d 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -363,7 +363,7 @@
dest.writeInt(requestId);
dest.writeString(type.name());
}
- public static final Creator<NetworkRequest> CREATOR =
+ public static final @android.annotation.NonNull Creator<NetworkRequest> CREATOR =
new Creator<NetworkRequest>() {
public NetworkRequest createFromParcel(Parcel in) {
NetworkCapabilities nc = NetworkCapabilities.CREATOR.createFromParcel(in);
diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java
index 97fb3fb..292cf50 100644
--- a/core/java/android/net/NetworkState.java
+++ b/core/java/android/net/NetworkState.java
@@ -87,7 +87,7 @@
}
@UnsupportedAppUsage
- public static final Creator<NetworkState> CREATOR = new Creator<NetworkState>() {
+ public static final @android.annotation.NonNull Creator<NetworkState> CREATOR = new Creator<NetworkState>() {
@Override
public NetworkState createFromParcel(Parcel in) {
return new NetworkState(in);
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 0ae29b1..ed410e2 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -16,10 +16,15 @@
package android.net;
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+
+import android.annotation.NonNull;
import android.annotation.UnsupportedAppUsage;
import android.net.shared.Inet4AddressUtils;
import android.os.Build;
import android.system.ErrnoException;
+import android.system.Os;
import android.util.Log;
import android.util.Pair;
@@ -480,4 +485,30 @@
}
return routedIPCount;
}
+
+ private static final int[] ADDRESS_FAMILIES = new int[] {AF_INET, AF_INET6};
+
+ /**
+ * Returns true if the hostname is weakly validated.
+ * @param hostname Name of host to validate.
+ * @return True if it's a valid-ish hostname.
+ *
+ * @hide
+ */
+ public static boolean isWeaklyValidatedHostname(@NonNull String hostname) {
+ // TODO(b/34953048): Use a validation method that permits more accurate,
+ // but still inexpensive, checking of likely valid DNS hostnames.
+ final String weakHostnameRegex = "^[a-zA-Z0-9_.-]+$";
+ if (!hostname.matches(weakHostnameRegex)) {
+ return false;
+ }
+
+ for (int address_family : ADDRESS_FAMILIES) {
+ if (Os.inet_pton(address_family, hostname) != null) {
+ return false;
+ }
+ }
+
+ return true;
+ }
}
diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java
index ef2269a..807c467 100644
--- a/core/java/android/net/ProxyInfo.java
+++ b/core/java/android/net/ProxyInfo.java
@@ -342,7 +342,7 @@
dest.writeStringArray(mParsedExclusionList);
}
- public static final Creator<ProxyInfo> CREATOR =
+ public static final @android.annotation.NonNull Creator<ProxyInfo> CREATOR =
new Creator<ProxyInfo>() {
public ProxyInfo createFromParcel(Parcel in) {
String host = null;
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index 5c0f758..c1c8f6e 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -486,7 +486,7 @@
/**
* Implement the Parcelable interface.
*/
- public static final Creator<RouteInfo> CREATOR =
+ public static final @android.annotation.NonNull Creator<RouteInfo> CREATOR =
new Creator<RouteInfo>() {
public RouteInfo createFromParcel(Parcel in) {
IpPrefix dest = in.readParcelable(null);
diff --git a/core/java/android/net/StaticIpConfiguration.java b/core/java/android/net/StaticIpConfiguration.java
index 99cf3a9..8b264ee 100644
--- a/core/java/android/net/StaticIpConfiguration.java
+++ b/core/java/android/net/StaticIpConfiguration.java
@@ -212,7 +212,7 @@
}
/** Implement the Parcelable interface */
- public static final Creator<StaticIpConfiguration> CREATOR =
+ public static final @android.annotation.NonNull Creator<StaticIpConfiguration> CREATOR =
new Creator<StaticIpConfiguration>() {
public StaticIpConfiguration createFromParcel(Parcel in) {
return readFromParcel(in);
diff --git a/core/java/android/net/TcpKeepalivePacketData.java b/core/java/android/net/TcpKeepalivePacketData.java
index f07dfb6..99d36c5 100644
--- a/core/java/android/net/TcpKeepalivePacketData.java
+++ b/core/java/android/net/TcpKeepalivePacketData.java
@@ -194,7 +194,7 @@
}
/** Parcelable Creator. */
- public static final Parcelable.Creator<TcpKeepalivePacketData> CREATOR =
+ public static final @android.annotation.NonNull Parcelable.Creator<TcpKeepalivePacketData> CREATOR =
new Parcelable.Creator<TcpKeepalivePacketData>() {
public TcpKeepalivePacketData createFromParcel(Parcel in) {
return new TcpKeepalivePacketData(in);
diff --git a/core/java/android/net/UidRange.java b/core/java/android/net/UidRange.java
index 793c82d..d4a4cf4 100644
--- a/core/java/android/net/UidRange.java
+++ b/core/java/android/net/UidRange.java
@@ -91,7 +91,7 @@
* The parceling code is autogenerated by the superclass.
*/
- public static final Creator<UidRange> CREATOR =
+ public static final @android.annotation.NonNull Creator<UidRange> CREATOR =
new Creator<UidRange>() {
@Override
public UidRange createFromParcel(Parcel in) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 219cf33..72f7a68 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -84,6 +84,7 @@
import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
import android.net.NetworkConfig;
+import android.net.NetworkFactory;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkMisc;
@@ -1073,7 +1074,8 @@
handleRegisterNetworkRequest(new NetworkRequestInfo(
null, networkRequest, new Binder()));
} else {
- handleReleaseNetworkRequest(networkRequest, Process.SYSTEM_UID);
+ handleReleaseNetworkRequest(networkRequest, Process.SYSTEM_UID,
+ /* callOnUnavailable */ false);
}
}
@@ -2701,11 +2703,25 @@
return true;
}
+ private boolean maybeHandleNetworkFactoryMessage(Message msg) {
+ switch (msg.what) {
+ default:
+ return false;
+ case NetworkFactory.EVENT_UNFULFILLABLE_REQUEST: {
+ handleReleaseNetworkRequest((NetworkRequest) msg.obj, msg.sendingUid,
+ /* callOnUnavailable */ true);
+ break;
+ }
+ }
+ return true;
+ }
+
@Override
public void handleMessage(Message msg) {
- if (!maybeHandleAsyncChannelMessage(msg) &&
- !maybeHandleNetworkMonitorMessage(msg) &&
- !maybeHandleNetworkAgentInfoMessage(msg)) {
+ if (!maybeHandleAsyncChannelMessage(msg)
+ && !maybeHandleNetworkMonitorMessage(msg)
+ && !maybeHandleNetworkAgentInfoMessage(msg)
+ && !maybeHandleNetworkFactoryMessage(msg)) {
maybeHandleNetworkAgentMessage(msg);
}
}
@@ -2870,12 +2886,24 @@
if (mNetworkFactoryInfos.containsKey(msg.replyTo)) {
if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
if (VDBG) log("NetworkFactory connected");
+ // Finish setting up the full connection
+ mNetworkFactoryInfos.get(msg.replyTo).asyncChannel.sendMessage(
+ AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
// A network factory has connected. Send it all current NetworkRequests.
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
if (nri.request.isListen()) continue;
NetworkAgentInfo nai = getNetworkForRequest(nri.request.requestId);
- ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK,
- (nai != null ? nai.getCurrentScore() : 0), 0, nri.request);
+ final int score;
+ final int serial;
+ if (nai != null) {
+ score = nai.getCurrentScore();
+ serial = nai.factorySerialNumber;
+ } else {
+ score = 0;
+ serial = NetworkFactory.SerialNumber.NONE;
+ }
+ ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, serial,
+ nri.request);
}
} else {
loge("Error connecting NetworkFactory");
@@ -2973,7 +3001,7 @@
NetworkAgentInfo currentNetwork = getNetworkForRequest(request.requestId);
if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) {
clearNetworkForRequest(request.requestId);
- sendUpdatedScoreToFactories(request, 0);
+ sendUpdatedScoreToFactories(request, null);
}
}
nai.clearLingerState();
@@ -3031,7 +3059,8 @@
if (existingRequest != null) { // remove the existing request.
if (DBG) log("Replacing " + existingRequest.request + " with "
+ nri.request + " because their intents matched.");
- handleReleaseNetworkRequest(existingRequest.request, getCallingUid());
+ handleReleaseNetworkRequest(existingRequest.request, getCallingUid(),
+ /* callOnUnavailable */ false);
}
handleRegisterNetworkRequest(nri);
}
@@ -3049,7 +3078,7 @@
}
rematchAllNetworksAndRequests(null, 0);
if (nri.request.isRequest() && getNetworkForRequest(nri.request.requestId) == null) {
- sendUpdatedScoreToFactories(nri.request, 0);
+ sendUpdatedScoreToFactories(nri.request, null);
}
}
@@ -3057,7 +3086,7 @@
int callingUid) {
NetworkRequestInfo nri = findExistingNetworkRequestInfo(pendingIntent);
if (nri != null) {
- handleReleaseNetworkRequest(nri.request, callingUid);
+ handleReleaseNetworkRequest(nri.request, callingUid, /* callOnUnavailable */ false);
}
}
@@ -3140,7 +3169,8 @@
callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_UNAVAIL, 0);
}
- private void handleReleaseNetworkRequest(NetworkRequest request, int callingUid) {
+ private void handleReleaseNetworkRequest(NetworkRequest request, int callingUid,
+ boolean callOnUnavailable) {
final NetworkRequestInfo nri =
getNriForAppRequest(request, callingUid, "release NetworkRequest");
if (nri == null) {
@@ -3150,6 +3180,9 @@
log("releasing " + nri.request + " (release request)");
}
handleRemoveNetworkRequest(nri);
+ if (callOnUnavailable) {
+ callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_UNAVAIL, 0);
+ }
}
private void handleRemoveNetworkRequest(final NetworkRequestInfo nri) {
@@ -3651,7 +3684,8 @@
break;
}
case EVENT_RELEASE_NETWORK_REQUEST: {
- handleReleaseNetworkRequest((NetworkRequest) msg.obj, msg.arg1);
+ handleReleaseNetworkRequest((NetworkRequest) msg.obj, msg.arg1,
+ /* callOnUnavailable */ false);
break;
}
case EVENT_SET_ACCEPT_UNVALIDATED: {
@@ -4819,11 +4853,14 @@
public final String name;
public final Messenger messenger;
public final AsyncChannel asyncChannel;
+ public final int factorySerialNumber;
- public NetworkFactoryInfo(String name, Messenger messenger, AsyncChannel asyncChannel) {
+ NetworkFactoryInfo(String name, Messenger messenger, AsyncChannel asyncChannel,
+ int factorySerialNumber) {
this.name = name;
this.messenger = messenger;
this.asyncChannel = asyncChannel;
+ this.factorySerialNumber = factorySerialNumber;
}
}
@@ -5184,10 +5221,12 @@
}
@Override
- public void registerNetworkFactory(Messenger messenger, String name) {
+ public int registerNetworkFactory(Messenger messenger, String name) {
enforceConnectivityInternalPermission();
- NetworkFactoryInfo nfi = new NetworkFactoryInfo(name, messenger, new AsyncChannel());
+ NetworkFactoryInfo nfi = new NetworkFactoryInfo(name, messenger, new AsyncChannel(),
+ NetworkFactory.SerialNumber.nextSerialNumber());
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, nfi));
+ return nfi.factorySerialNumber;
}
private void handleRegisterNetworkFactory(NetworkFactoryInfo nfi) {
@@ -5292,9 +5331,35 @@
return nri.request.requestId == mDefaultRequest.requestId;
}
+ // TODO : remove this method. It's a stopgap measure to help sheperding a number of dependent
+ // changes that would conflict throughout the automerger graph. Having this method temporarily
+ // helps with the process of going through with all these dependent changes across the entire
+ // tree.
public int registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
int currentScore, NetworkMisc networkMisc) {
+ return registerNetworkAgent(messenger, networkInfo, linkProperties, networkCapabilities,
+ currentScore, networkMisc, NetworkFactory.SerialNumber.NONE);
+ }
+
+ /**
+ * Register a new agent with ConnectivityService to handle a network.
+ *
+ * @param messenger a messenger for ConnectivityService to contact the agent asynchronously.
+ * @param networkInfo the initial info associated with this network. It can be updated later :
+ * see {@link #updateNetworkInfo}.
+ * @param linkProperties the initial link properties of this network. They can be updated
+ * later : see {@link #updateLinkProperties}.
+ * @param networkCapabilities the initial capabilites of this network. They can be updated
+ * later : see {@link #updateNetworkCapabilities}.
+ * @param currentScore the initial score of the network. See
+ * {@link NetworkAgentInfo#getCurrentScore}.
+ * @param networkMisc metadata about the network. This is never updated.
+ * @param factorySerialNumber the serial number of the factory owning this NetworkAgent.
+ */
+ public int registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
+ LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
+ int currentScore, NetworkMisc networkMisc, int factorySerialNumber) {
enforceConnectivityInternalPermission();
LinkProperties lp = new LinkProperties(linkProperties);
@@ -5304,7 +5369,8 @@
final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
new Network(reserveNetId()), new NetworkInfo(networkInfo), lp, nc, currentScore,
- mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd, mNMS);
+ mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd, mNMS,
+ factorySerialNumber);
// Make sure the network capabilities reflect what the agent info says.
nai.networkCapabilities = mixInCapabilities(nai, nc);
final String extraInfo = networkInfo.getExtraInfo();
@@ -5731,17 +5797,23 @@
NetworkRequest nr = nai.requestAt(i);
// Don't send listening requests to factories. b/17393458
if (nr.isListen()) continue;
- sendUpdatedScoreToFactories(nr, nai.getCurrentScore());
+ sendUpdatedScoreToFactories(nr, nai);
}
}
- private void sendUpdatedScoreToFactories(NetworkRequest networkRequest, int score) {
+ private void sendUpdatedScoreToFactories(NetworkRequest networkRequest, NetworkAgentInfo nai) {
+ int score = 0;
+ int serial = 0;
+ if (nai != null) {
+ score = nai.getCurrentScore();
+ serial = nai.factorySerialNumber;
+ }
if (VDBG || DDBG){
log("sending new Min Network Score(" + score + "): " + networkRequest.toString());
}
for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) {
- nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, 0,
- networkRequest);
+ nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score,
+ serial, networkRequest);
}
}
@@ -6019,7 +6091,7 @@
// TODO - this could get expensive if we have a lot of requests for this
// network. Think about if there is a way to reduce this. Push
// netid->request mapping to each factory?
- sendUpdatedScoreToFactories(nri.request, score);
+ sendUpdatedScoreToFactories(nri.request, newNetwork);
if (isDefaultRequest(nri)) {
isNewDefault = true;
oldDefaultNetwork = currentNetwork;
@@ -6043,7 +6115,7 @@
newNetwork.removeRequest(nri.request.requestId);
if (currentNetwork == newNetwork) {
clearNetworkForRequest(nri.request.requestId);
- sendUpdatedScoreToFactories(nri.request, 0);
+ sendUpdatedScoreToFactories(nri.request, null);
} else {
Slog.wtf(TAG, "BUG: Removing request " + nri.request.requestId + " from " +
newNetwork.name() +
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 65eb158..8f2825c 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -238,6 +238,8 @@
public final Messenger messenger;
public final AsyncChannel asyncChannel;
+ public final int factorySerialNumber;
+
// Used by ConnectivityService to keep track of 464xlat.
public final Nat464Xlat clatd;
@@ -253,7 +255,7 @@
public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info,
LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler,
NetworkMisc misc, ConnectivityService connService, INetd netd,
- INetworkManagementService nms) {
+ INetworkManagementService nms, int factorySerialNumber) {
this.messenger = messenger;
asyncChannel = ac;
network = net;
@@ -266,6 +268,7 @@
mContext = context;
mHandler = handler;
networkMisc = misc;
+ this.factorySerialNumber = factorySerialNumber;
}
/**
diff --git a/tests/net/java/android/net/MacAddressTest.java b/tests/net/java/android/net/MacAddressTest.java
index b0e5fb1..daf187d 100644
--- a/tests/net/java/android/net/MacAddressTest.java
+++ b/tests/net/java/android/net/MacAddressTest.java
@@ -254,6 +254,39 @@
}
}
+ @Test
+ public void testMatches() {
+ // match 4 bytes prefix
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:dd:00:00"),
+ MacAddress.fromString("ff:ff:ff:ff:00:00")));
+
+ // match bytes 0,1,2 and 5
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:00:00:11"),
+ MacAddress.fromString("ff:ff:ff:00:00:ff")));
+
+ // match 34 bit prefix
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:dd:c0:00"),
+ MacAddress.fromString("ff:ff:ff:ff:c0:00")));
+
+ // fail to match 36 bit prefix
+ assertFalse(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:dd:40:00"),
+ MacAddress.fromString("ff:ff:ff:ff:f0:00")));
+
+ // match all 6 bytes
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:dd:ee:11"),
+ MacAddress.fromString("ff:ff:ff:ff:ff:ff")));
+
+ // match none of 6 bytes
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("00:00:00:00:00:00"),
+ MacAddress.fromString("00:00:00:00:00:00")));
+ }
+
/**
* Tests that link-local address generation from MAC is valid.
*/
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 70eb70b..985d667 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -154,6 +154,7 @@
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
+import android.util.SparseArray;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -507,7 +508,7 @@
mNetworkAgent = new NetworkAgent(mHandlerThread.getLooper(), mServiceContext,
"Mock-" + typeName, mNetworkInfo, mNetworkCapabilities,
- linkProperties, mScore, new NetworkMisc()) {
+ linkProperties, mScore, new NetworkMisc(), NetworkFactory.SerialNumber.NONE) {
@Override
public void unwanted() { mDisconnected.open(); }
@@ -742,7 +743,7 @@
/**
* A NetworkFactory that allows tests to wait until any in-flight NetworkRequest add or remove
* operations have been processed. Before ConnectivityService can add or remove any requests,
- * the factory must be told to expect those operations by calling expectAddRequests or
+ * the factory must be told to expect those operations by calling expectAddRequestsWithScores or
* expectRemoveRequests.
*/
private static class MockNetworkFactory extends NetworkFactory {
@@ -751,19 +752,26 @@
private final AtomicBoolean mNetworkStarted = new AtomicBoolean(false);
// Used to expect that requests be removed or added on a separate thread, without sleeping.
- // Callers can call either expectAddRequests() or expectRemoveRequests() exactly once, then
- // cause some other thread to add or remove requests, then call waitForRequests(). We can
- // either expect requests to be added or removed, but not both, because CountDownLatch can
- // only count in one direction.
- private CountDownLatch mExpectations;
+ // Callers can call either expectAddRequestsWithScores() or expectRemoveRequests() exactly
+ // once, then cause some other thread to add or remove requests, then call
+ // waitForRequests().
+ // It is not possible to wait for both add and remove requests. When adding, the queue
+ // contains the expected score. When removing, the value is unused, all matters is the
+ // number of objects in the queue.
+ private final LinkedBlockingQueue<Integer> mExpectations;
// Whether we are currently expecting requests to be added or removed. Valid only if
- // mExpectations is non-null.
+ // mExpectations is non-empty.
private boolean mExpectingAdditions;
+ // Used to collect the networks requests managed by this factory. This is a duplicate of
+ // the internal information stored in the NetworkFactory (which is private).
+ private SparseArray<NetworkRequest> mNetworkRequests = new SparseArray<>();
+
public MockNetworkFactory(Looper looper, Context context, String logTag,
NetworkCapabilities filter) {
super(looper, context, logTag, filter);
+ mExpectations = new LinkedBlockingQueue<>();
}
public int getMyRequestCount() {
@@ -795,74 +803,96 @@
}
@Override
- protected void handleAddRequest(NetworkRequest request, int score) {
- // If we're expecting anything, we must be expecting additions.
- if (mExpectations != null && !mExpectingAdditions) {
- fail("Can't add requests while expecting requests to be removed");
- }
+ protected void handleAddRequest(NetworkRequest request, int score,
+ int factorySerialNumber) {
+ synchronized (mExpectations) {
+ final Integer expectedScore = mExpectations.poll(); // null if the queue is empty
- // Add the request.
- super.handleAddRequest(request, score);
+ assertNotNull("Added more requests than expected (" + request + " score : "
+ + score + ")", expectedScore);
+ // If we're expecting anything, we must be expecting additions.
+ if (!mExpectingAdditions) {
+ fail("Can't add requests while expecting requests to be removed");
+ }
+ if (expectedScore != score) {
+ fail("Expected score was " + expectedScore + " but actual was " + score
+ + " in added request");
+ }
- // Reduce the number of request additions we're waiting for.
- if (mExpectingAdditions) {
- assertTrue("Added more requests than expected", mExpectations.getCount() > 0);
- mExpectations.countDown();
+ // Add the request.
+ mNetworkRequests.put(request.requestId, request);
+ super.handleAddRequest(request, score, factorySerialNumber);
+ mExpectations.notify();
}
}
@Override
protected void handleRemoveRequest(NetworkRequest request) {
- // If we're expecting anything, we must be expecting removals.
- if (mExpectations != null && mExpectingAdditions) {
- fail("Can't remove requests while expecting requests to be added");
- }
+ synchronized (mExpectations) {
+ final Integer expectedScore = mExpectations.poll(); // null if the queue is empty
- // Remove the request.
- super.handleRemoveRequest(request);
+ assertTrue("Removed more requests than expected", expectedScore != null);
+ // If we're expecting anything, we must be expecting removals.
+ if (mExpectingAdditions) {
+ fail("Can't remove requests while expecting requests to be added");
+ }
- // Reduce the number of request removals we're waiting for.
- if (!mExpectingAdditions) {
- assertTrue("Removed more requests than expected", mExpectations.getCount() > 0);
- mExpectations.countDown();
+ // Remove the request.
+ mNetworkRequests.remove(request.requestId);
+ super.handleRemoveRequest(request);
+ mExpectations.notify();
}
}
+ // Trigger releasing the request as unfulfillable
+ public void triggerUnfulfillable(NetworkRequest r) {
+ super.releaseRequestAsUnfulfillableByAnyFactory(r);
+ }
+
private void assertNoExpectations() {
- if (mExpectations != null) {
- fail("Can't add expectation, " + mExpectations.getCount() + " already pending");
+ if (mExpectations.size() != 0) {
+ fail("Can't add expectation, " + mExpectations.size() + " already pending");
}
}
- // Expects that count requests will be added.
- public void expectAddRequests(final int count) {
+ // Expects that requests with the specified scores will be added.
+ public void expectAddRequestsWithScores(final int... scores) {
assertNoExpectations();
mExpectingAdditions = true;
- mExpectations = new CountDownLatch(count);
+ for (int score : scores) {
+ mExpectations.add(score);
+ }
}
// Expects that count requests will be removed.
public void expectRemoveRequests(final int count) {
assertNoExpectations();
mExpectingAdditions = false;
- mExpectations = new CountDownLatch(count);
+ for (int i = 0; i < count; ++i) {
+ mExpectations.add(0); // For removals the score is ignored so any value will do.
+ }
}
// Waits for the expected request additions or removals to happen within a timeout.
public void waitForRequests() throws InterruptedException {
- assertNotNull("Nothing to wait for", mExpectations);
- mExpectations.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
- final long count = mExpectations.getCount();
+ final long deadline = SystemClock.elapsedRealtime() + TIMEOUT_MS;
+ synchronized (mExpectations) {
+ while (mExpectations.size() > 0 && SystemClock.elapsedRealtime() < deadline) {
+ mExpectations.wait(deadline - SystemClock.elapsedRealtime());
+ }
+ }
+ final long count = mExpectations.size();
final String msg = count + " requests still not " +
(mExpectingAdditions ? "added" : "removed") +
" after " + TIMEOUT_MS + " ms";
assertEquals(msg, 0, count);
- mExpectations = null;
}
- public void waitForNetworkRequests(final int count) throws InterruptedException {
+ public SparseArray<NetworkRequest> waitForNetworkRequests(final int count)
+ throws InterruptedException {
waitForRequests();
assertEquals(count, getMyRequestCount());
+ return mNetworkRequests;
}
}
@@ -2312,6 +2342,12 @@
callback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
}
+ private int[] makeIntArray(final int size, final int value) {
+ final int[] array = new int[size];
+ Arrays.fill(array, value);
+ return array;
+ }
+
private void tryNetworkFactoryRequests(int capability) throws Exception {
// Verify NOT_RESTRICTED is set appropriately
final NetworkCapabilities nc = new NetworkRequest.Builder().addCapability(capability)
@@ -2333,7 +2369,7 @@
mServiceContext, "testFactory", filter);
testFactory.setScoreFilter(40);
ConditionVariable cv = testFactory.getNetworkStartedCV();
- testFactory.expectAddRequests(1);
+ testFactory.expectAddRequestsWithScores(0);
testFactory.register();
testFactory.waitForNetworkRequests(1);
int expectedRequestCount = 1;
@@ -2344,7 +2380,7 @@
assertFalse(testFactory.getMyStartRequested());
NetworkRequest request = new NetworkRequest.Builder().addCapability(capability).build();
networkCallback = new NetworkCallback();
- testFactory.expectAddRequests(1);
+ testFactory.expectAddRequestsWithScores(0); // New request
mCm.requestNetwork(request, networkCallback);
expectedRequestCount++;
testFactory.waitForNetworkRequests(expectedRequestCount);
@@ -2364,7 +2400,7 @@
// When testAgent connects, ConnectivityService will re-send us all current requests with
// the new score. There are expectedRequestCount such requests, and we must wait for all of
// them.
- testFactory.expectAddRequests(expectedRequestCount);
+ testFactory.expectAddRequestsWithScores(makeIntArray(expectedRequestCount, 50));
testAgent.connect(false);
testAgent.addCapability(capability);
waitFor(cv);
@@ -2372,7 +2408,7 @@
assertFalse(testFactory.getMyStartRequested());
// Bring in a bunch of requests.
- testFactory.expectAddRequests(10);
+ testFactory.expectAddRequestsWithScores(makeIntArray(10, 50));
assertEquals(expectedRequestCount, testFactory.getMyRequestCount());
ConnectivityManager.NetworkCallback[] networkCallbacks =
new ConnectivityManager.NetworkCallback[10];
@@ -2395,8 +2431,11 @@
// Drop the higher scored network.
cv = testFactory.getNetworkStartedCV();
+ // With the default network disconnecting, the requests are sent with score 0 to factories.
+ testFactory.expectAddRequestsWithScores(makeIntArray(expectedRequestCount, 0));
testAgent.disconnect();
waitFor(cv);
+ testFactory.waitForNetworkRequests(expectedRequestCount);
assertEquals(expectedRequestCount, testFactory.getMyRequestCount());
assertTrue(testFactory.getMyStartRequested());
@@ -3318,22 +3357,23 @@
testFactory.setScoreFilter(40);
// Register the factory and expect it to start looking for a network.
- testFactory.expectAddRequests(1);
+ testFactory.expectAddRequestsWithScores(0); // Score 0 as the request is not served yet.
testFactory.register();
testFactory.waitForNetworkRequests(1);
assertTrue(testFactory.getMyStartRequested());
// Bring up wifi. The factory stops looking for a network.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
- testFactory.expectAddRequests(2); // Because the default request changes score twice.
+ // Score 60 - 40 penalty for not validated yet, then 60 when it validates
+ testFactory.expectAddRequestsWithScores(20, 60);
mWiFiNetworkAgent.connect(true);
- testFactory.waitForNetworkRequests(1);
+ testFactory.waitForRequests();
assertFalse(testFactory.getMyStartRequested());
ContentResolver cr = mServiceContext.getContentResolver();
// Turn on mobile data always on. The factory starts looking again.
- testFactory.expectAddRequests(1);
+ testFactory.expectAddRequestsWithScores(0); // Always on requests comes up with score 0
setAlwaysOnNetworks(true);
testFactory.waitForNetworkRequests(2);
assertTrue(testFactory.getMyStartRequested());
@@ -3341,7 +3381,7 @@
// Bring up cell data and check that the factory stops looking.
assertLength(1, mCm.getAllNetworks());
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
- testFactory.expectAddRequests(2); // Because the cell request changes score twice.
+ testFactory.expectAddRequestsWithScores(10, 50); // Unvalidated, then validated
mCellNetworkAgent.connect(true);
cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
testFactory.waitForNetworkRequests(2);
@@ -3636,6 +3676,55 @@
networkCallback.assertNoCallback();
}
+ /**
+ * Validate the callback flow for a factory releasing a request as unfulfillable.
+ */
+ @Test
+ public void testUnfulfillableNetworkRequest() throws Exception {
+ NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
+ NetworkCapabilities.TRANSPORT_WIFI).build();
+ final TestNetworkCallback networkCallback = new TestNetworkCallback();
+
+ final HandlerThread handlerThread = new HandlerThread("testUnfulfillableNetworkRequest");
+ handlerThread.start();
+ NetworkCapabilities filter = new NetworkCapabilities()
+ .addTransportType(TRANSPORT_WIFI)
+ .addCapability(NET_CAPABILITY_INTERNET);
+ final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
+ mServiceContext, "testFactory", filter);
+ testFactory.setScoreFilter(40);
+
+ // Register the factory and expect it to receive the default request.
+ testFactory.expectAddRequestsWithScores(0);
+ testFactory.register();
+ SparseArray<NetworkRequest> requests = testFactory.waitForNetworkRequests(1);
+
+ assertEquals(1, requests.size()); // have 1 request at this point
+ int origRequestId = requests.valueAt(0).requestId;
+
+ // Now file the test request and expect it.
+ testFactory.expectAddRequestsWithScores(0);
+ mCm.requestNetwork(nr, networkCallback);
+ requests = testFactory.waitForNetworkRequests(2); // have 2 requests at this point
+
+ int newRequestId = 0;
+ for (int i = 0; i < requests.size(); ++i) {
+ if (requests.valueAt(i).requestId != origRequestId) {
+ newRequestId = requests.valueAt(i).requestId;
+ break;
+ }
+ }
+
+ // 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();
+
+ testFactory.unregister();
+ handlerThread.quit();
+ }
+
private static class TestKeepaliveCallback extends PacketKeepaliveCallback {
public static enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR };
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index 38352b3..6de4aa1 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -35,6 +35,7 @@
import android.net.INetd;
import android.net.Network;
import android.net.NetworkCapabilities;
+import android.net.NetworkFactory;
import android.net.NetworkInfo;
import android.net.NetworkMisc;
import android.os.INetworkManagementService;
@@ -352,7 +353,8 @@
caps.addCapability(0);
caps.addTransportType(transport);
NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null,
- caps, 50, mCtx, null, mMisc, mConnService, mNetd, mNMS);
+ caps, 50, mCtx, null, mMisc, mConnService, mNetd, mNMS,
+ NetworkFactory.SerialNumber.NONE);
nai.everValidated = true;
return nai;
}