Allow network providers to set the linger duration.
Test: atest CtsNetTestCases:NetworkAgentTest#testSetLingerDuration
CTS-Coverage-Bug: 184796264
Bug: 184227264
Merged-In: I3c2563d4ae4e3715d0c6270344ba8f7ef067872f
Merged-In: I7f420faa40863385114705d6971cf00887d03318
Change-Id: I7f420faa40863385114705d6971cf00887d03318
(cherry-picked from ag/14100410)
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index b804a51..eb7dccc 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -1400,8 +1400,8 @@
new NetworkInfo(TYPE_NONE, 0, "", ""),
new LinkProperties(), new NetworkCapabilities(),
new NetworkScore.Builder().setLegacyInt(0).build(), mContext, null,
- new NetworkAgentConfig(), this, null, null, 0, INVALID_UID, mQosCallbackTracker,
- mDeps);
+ new NetworkAgentConfig(), this, null, null, 0, INVALID_UID,
+ mLingerDelayMs, mQosCallbackTracker, mDeps);
}
private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) {
@@ -3234,6 +3234,11 @@
} else {
logwtf(nai.toShortString() + " set invalid teardown delay " + msg.arg1);
}
+ break;
+ }
+ case NetworkAgent.EVENT_LINGER_DURATION_CHANGED: {
+ nai.setLingerDuration((int) arg.second);
+ break;
}
}
}
@@ -6597,7 +6602,8 @@
final NetworkAgentInfo nai = new NetworkAgentInfo(na,
new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig),
- this, mNetd, mDnsResolver, providerId, uid, mQosCallbackTracker, mDeps);
+ this, mNetd, mDnsResolver, providerId, uid, mLingerDelayMs,
+ mQosCallbackTracker, mDeps);
// Make sure the LinkProperties and NetworkCapabilities reflect what the agent info says.
processCapabilitiesFromAgent(nai, nc);
@@ -7841,7 +7847,7 @@
log(" accepting network in place of " + previousSatisfier.toShortString());
}
previousSatisfier.removeRequest(previousRequest.requestId);
- previousSatisfier.lingerRequest(previousRequest.requestId, now, mLingerDelayMs);
+ previousSatisfier.lingerRequest(previousRequest.requestId, now);
} else {
if (VDBG || DDBG) log(" accepting network in place of null");
}
diff --git a/service/src/com/android/server/connectivity/NetworkAgentInfo.java b/service/src/com/android/server/connectivity/NetworkAgentInfo.java
index 851096d..18becd4 100644
--- a/service/src/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/service/src/com/android/server/connectivity/NetworkAgentInfo.java
@@ -59,6 +59,7 @@
import com.android.server.ConnectivityService;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.NoSuchElementException;
@@ -281,6 +282,9 @@
*/
public static final int ARG_AGENT_SUCCESS = 1;
+ // How long this network should linger for.
+ private int mLingerDurationMs;
+
// All inactivity timers for this network, sorted by expiry time. A timer is added whenever
// a request is moved to a network with a better score, regardless of whether the network is or
// was lingering or not. An inactivity timer is also added when a network connects
@@ -349,7 +353,8 @@
@NonNull NetworkScore score, Context context,
Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd,
IDnsResolver dnsResolver, int factorySerialNumber, int creatorUid,
- QosCallbackTracker qosCallbackTracker, ConnectivityService.Dependencies deps) {
+ int lingerDurationMs, QosCallbackTracker qosCallbackTracker,
+ ConnectivityService.Dependencies deps) {
Objects.requireNonNull(net);
Objects.requireNonNull(info);
Objects.requireNonNull(lp);
@@ -370,6 +375,7 @@
mHandler = handler;
this.factorySerialNumber = factorySerialNumber;
this.creatorUid = creatorUid;
+ mLingerDurationMs = lingerDurationMs;
mQosCallbackTracker = qosCallbackTracker;
}
@@ -685,6 +691,12 @@
mHandler.obtainMessage(NetworkAgent.EVENT_TEARDOWN_DELAY_CHANGED,
teardownDelayMs, 0, new Pair<>(NetworkAgentInfo.this, null)).sendToTarget();
}
+
+ @Override
+ public void sendLingerDuration(final int durationMs) {
+ mHandler.obtainMessage(NetworkAgent.EVENT_LINGER_DURATION_CHANGED,
+ new Pair<>(NetworkAgentInfo.this, durationMs)).sendToTarget();
+ }
}
/**
@@ -974,13 +986,14 @@
/**
* Sets the specified requestId to linger on this network for the specified time. Called by
- * ConnectivityService when the request is moved to another network with a higher score, or
+ * ConnectivityService when any request is moved to another network with a higher score, or
* when a network is newly created.
*
* @param requestId The requestId of the request that no longer need to be served by this
* network. Or {@link NetworkRequest.REQUEST_ID_NONE} if this is the
- * {@code LingerTimer} for a newly created network.
+ * {@code InactivityTimer} for a newly created network.
*/
+ // TODO: Consider creating a dedicated function for nascent network, e.g. start/stopNascent.
public void lingerRequest(int requestId, long now, long duration) {
if (mInactivityTimerForRequest.get(requestId) != null) {
// Cannot happen. Once a request is lingering on a particular network, we cannot
@@ -996,6 +1009,19 @@
}
/**
+ * Sets the specified requestId to linger on this network for the timeout set when
+ * initializing or modified by {@link #setLingerDuration(int)}. Called by
+ * ConnectivityService when any request is moved to another network with a higher score.
+ *
+ * @param requestId The requestId of the request that no longer need to be served by this
+ * network.
+ * @param now current system timestamp obtained by {@code SystemClock.elapsedRealtime}.
+ */
+ public void lingerRequest(int requestId, long now) {
+ lingerRequest(requestId, now, mLingerDurationMs);
+ }
+
+ /**
* Cancel lingering. Called by ConnectivityService when a request is added to this network.
* Returns true if the given requestId was lingering on this network, false otherwise.
*/
@@ -1032,6 +1058,7 @@
}
if (newExpiry > 0) {
+ // If the newExpiry timestamp is in the past, the wakeup message will fire immediately.
mInactivityMessage = new WakeupMessage(
mContext, mHandler,
"NETWORK_LINGER_COMPLETE." + network.getNetId() /* cmdName */,
@@ -1061,8 +1088,33 @@
}
/**
- * Return whether the network is just connected and about to be torn down because of not
- * satisfying any request.
+ * Set the linger duration for this NAI.
+ * @param durationMs The new linger duration, in milliseconds.
+ */
+ public void setLingerDuration(final int durationMs) {
+ final long diff = durationMs - mLingerDurationMs;
+ final ArrayList<InactivityTimer> newTimers = new ArrayList<>();
+ for (final InactivityTimer timer : mInactivityTimers) {
+ if (timer.requestId == NetworkRequest.REQUEST_ID_NONE) {
+ // Don't touch nascent timer, re-add as is.
+ newTimers.add(timer);
+ } else {
+ newTimers.add(new InactivityTimer(timer.requestId, timer.expiryMs + diff));
+ }
+ }
+ mInactivityTimers.clear();
+ mInactivityTimers.addAll(newTimers);
+ updateInactivityTimer();
+ mLingerDurationMs = durationMs;
+ }
+
+ /**
+ * Return whether the network satisfies no request, but is still being kept up
+ * because it has just connected less than
+ * {@code ConnectivityService#DEFAULT_NASCENT_DELAY_MS}ms ago and is thus still considered
+ * nascent. Note that nascent mechanism uses inactivity timer which isn't
+ * associated with a request. Thus, use {@link NetworkRequest#REQUEST_ID_NONE} to identify it.
+ *
*/
public boolean isNascent() {
return mInactive && mInactivityTimers.size() == 1