Merge "[VCN09] Rename linger timer"

This commit is contained in:
Junyu Lai
2021-02-05 09:29:12 +00:00
committed by Gerrit Code Review
2 changed files with 81 additions and 75 deletions

View File

@@ -2726,9 +2726,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
pw.println(nai.requestAt(i).toString());
}
pw.decreaseIndent();
pw.println("Lingered:");
pw.println("Inactivity Timers:");
pw.increaseIndent();
nai.dumpLingerTimers(pw);
nai.dumpInactivityTimers(pw);
pw.decreaseIndent();
pw.decreaseIndent();
}
@@ -3323,27 +3323,27 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
/**
* Updates the linger state from the network requests inside the NAI.
* Updates the inactivity state from the network requests inside the NAI.
* @param nai the agent info to update
* @param now the timestamp of the event causing this update
* @return whether the network was lingered as a result of this update
* @return whether the network was inactive as a result of this update
*/
private boolean updateLingerState(@NonNull final NetworkAgentInfo nai, final long now) {
// 1. Update the linger timer. If it's changed, reschedule or cancel the alarm.
// 2. If the network was lingering and there are now requests, unlinger it.
private boolean updateInactivityState(@NonNull final NetworkAgentInfo nai, final long now) {
// 1. Update the inactivity timer. If it's changed, reschedule or cancel the alarm.
// 2. If the network was inactive and there are now requests, unset inactive.
// 3. If this network is unneeded (which implies it is not lingering), and there is at least
// one lingered request, start lingering.
nai.updateLingerTimer();
// one lingered request, set inactive.
nai.updateInactivityTimer();
if (nai.isLingering() && nai.numForegroundNetworkRequests() > 0) {
if (DBG) log("Unlingering " + nai.toShortString());
nai.unlinger();
if (DBG) log("Unsetting inactive " + nai.toShortString());
nai.unsetInactive();
logNetworkEvent(nai, NetworkEvent.NETWORK_UNLINGER);
} else if (unneeded(nai, UnneededFor.LINGER) && nai.getLingerExpiry() > 0) {
} else if (unneeded(nai, UnneededFor.LINGER) && nai.getInactivityExpiry() > 0) {
if (DBG) {
final int lingerTime = (int) (nai.getLingerExpiry() - now);
log("Lingering " + nai.toShortString() + " for " + lingerTime + "ms");
final int lingerTime = (int) (nai.getInactivityExpiry() - now);
log("Setting inactive " + nai.toShortString() + " for " + lingerTime + "ms");
}
nai.linger();
nai.setInactive();
logNetworkEvent(nai, NetworkEvent.NETWORK_LINGER);
return true;
}
@@ -3481,7 +3481,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
}
nai.clearLingerState();
nai.clearInactivityState();
// TODO: mLegacyTypeTracker.remove seems redundant given there's a full rematch right after.
// Currently, deleting it breaks tests that check for the default network disconnecting.
// Find out why, fix the rematch code, and delete this.
@@ -3823,7 +3823,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// If there are still lingered requests on this network, don't tear it down,
// but resume lingering instead.
final long now = SystemClock.elapsedRealtime();
if (updateLingerState(nai, now)) {
if (updateInactivityState(nai, now)) {
notifyNetworkLosing(nai, now);
}
if (unneeded(nai, UnneededFor.TEARDOWN)) {
@@ -7238,7 +7238,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// If we get here it means that the last linger timeout for this network expired. So there
// must be no other active linger timers, and we must stop lingering.
oldNetwork.clearLingerState();
oldNetwork.clearInactivityState();
if (unneeded(oldNetwork, UnneededFor.TEARDOWN)) {
// Tear the network down.
@@ -7651,7 +7651,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// if the state has not changed : the source of truth is controlled with
// NetworkAgentInfo#lingerRequest and NetworkAgentInfo#unlingerRequest, which have been
// called while rematching the individual networks above.
if (updateLingerState(nai, now)) {
if (updateInactivityState(nai, now)) {
lingeredNetworks.add(nai);
}
}
@@ -7678,7 +7678,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Tear down all unneeded networks.
for (NetworkAgentInfo nai : mNetworkAgentInfos) {
if (unneeded(nai, UnneededFor.TEARDOWN)) {
if (nai.getLingerExpiry() > 0) {
if (nai.getInactivityExpiry() > 0) {
// This network has active linger timers and no requests, but is not
// lingering. Linger it.
//
@@ -7686,7 +7686,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// and became unneeded due to another network improving its score to the
// point where this network will no longer be able to satisfy any requests
// even if it validates.
if (updateLingerState(nai, now)) {
if (updateInactivityState(nai, now)) {
notifyNetworkLosing(nai, now);
}
} else {
@@ -7963,7 +7963,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Notify the requests on this NAI that the network is now lingered.
private void notifyNetworkLosing(@NonNull final NetworkAgentInfo nai, final long now) {
final int lingerTime = (int) (nai.getLingerExpiry() - now);
final int lingerTime = (int) (nai.getInactivityExpiry() - now);
notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOSING, lingerTime);
}

View File

@@ -210,23 +210,23 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
// network is taken down. This usually only happens to the default network. Lingering ends with
// either the linger timeout expiring and the network being taken down, or the network
// satisfying a request again.
public static class LingerTimer implements Comparable<LingerTimer> {
public static class InactivityTimer implements Comparable<InactivityTimer> {
public final int requestId;
public final long expiryMs;
public LingerTimer(int requestId, long expiryMs) {
public InactivityTimer(int requestId, long expiryMs) {
this.requestId = requestId;
this.expiryMs = expiryMs;
}
public boolean equals(Object o) {
if (!(o instanceof LingerTimer)) return false;
LingerTimer other = (LingerTimer) o;
if (!(o instanceof InactivityTimer)) return false;
InactivityTimer other = (InactivityTimer) o;
return (requestId == other.requestId) && (expiryMs == other.expiryMs);
}
public int hashCode() {
return Objects.hash(requestId, expiryMs);
}
public int compareTo(LingerTimer other) {
public int compareTo(InactivityTimer other) {
return (expiryMs != other.expiryMs) ?
Long.compare(expiryMs, other.expiryMs) :
Integer.compare(requestId, other.requestId);
@@ -269,30 +269,31 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
*/
public static final int ARG_AGENT_SUCCESS = 1;
// All linger timers for this network, sorted by expiry time. A linger timer is added whenever
// 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.
// TODO: determine if we can replace this with a smaller or unsorted data structure. (e.g.,
// SparseLongArray) combined with the timestamp of when the last timer is scheduled to fire.
private final SortedSet<LingerTimer> mLingerTimers = new TreeSet<>();
private final SortedSet<InactivityTimer> mInactivityTimers = new TreeSet<>();
// For fast lookups. Indexes into mLingerTimers by request ID.
private final SparseArray<LingerTimer> mLingerTimerForRequest = new SparseArray<>();
// For fast lookups. Indexes into mInactivityTimers by request ID.
private final SparseArray<InactivityTimer> mInactivityTimerForRequest = new SparseArray<>();
// Linger expiry timer. Armed whenever mLingerTimers is non-empty, regardless of whether the
// network is lingering or not. Always set to the expiry of the LingerTimer that expires last.
// When the timer fires, all linger state is cleared, and if the network has no requests, it is
// torn down.
private WakeupMessage mLingerMessage;
// Inactivity expiry timer. Armed whenever mInactivityTimers is non-empty, regardless of
// whether the network is inactive or not. Always set to the expiry of the mInactivityTimers
// that expires last. When the timer fires, all inactivity state is cleared, and if the network
// has no requests, it is torn down.
private WakeupMessage mInactivityMessage;
// Linger expiry. Holds the expiry time of the linger timer, or 0 if the timer is not armed.
private long mLingerExpiryMs;
// Inactivity expiry. Holds the expiry time of the inactivity timer, or 0 if the timer is not
// armed.
private long mInactivityExpiryMs;
// Whether the network is lingering or not. Must be maintained separately from the above because
// Whether the network is inactive or not. Must be maintained separately from the above because
// it depends on the state of other networks and requests, which only ConnectivityService knows.
// (Example: we don't linger a network if it would become the best for a NetworkRequest if it
// validated).
private boolean mLingering;
private boolean mInactive;
// This represents the quality of the network with no clear scale.
private int mScore;
@@ -898,17 +899,17 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
* ConnectivityService when the request is moved to another network with a higher score.
*/
public void lingerRequest(int requestId, long now, long duration) {
if (mLingerTimerForRequest.get(requestId) != null) {
if (mInactivityTimerForRequest.get(requestId) != null) {
// Cannot happen. Once a request is lingering on a particular network, we cannot
// re-linger it unless that network becomes the best for that request again, in which
// case we should have unlingered it.
Log.wtf(TAG, toShortString() + ": request " + requestId + " already lingered");
}
final long expiryMs = now + duration;
LingerTimer timer = new LingerTimer(requestId, expiryMs);
if (VDBG) Log.d(TAG, "Adding LingerTimer " + timer + " to " + toShortString());
mLingerTimers.add(timer);
mLingerTimerForRequest.put(requestId, timer);
InactivityTimer timer = new InactivityTimer(requestId, expiryMs);
if (VDBG) Log.d(TAG, "Adding InactivityTimer " + timer + " to " + toShortString());
mInactivityTimers.add(timer);
mInactivityTimerForRequest.put(requestId, timer);
}
/**
@@ -916,23 +917,25 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
* Returns true if the given requestId was lingering on this network, false otherwise.
*/
public boolean unlingerRequest(int requestId) {
LingerTimer timer = mLingerTimerForRequest.get(requestId);
InactivityTimer timer = mInactivityTimerForRequest.get(requestId);
if (timer != null) {
if (VDBG) Log.d(TAG, "Removing LingerTimer " + timer + " from " + toShortString());
mLingerTimers.remove(timer);
mLingerTimerForRequest.remove(requestId);
if (VDBG) {
Log.d(TAG, "Removing InactivityTimer " + timer + " from " + toShortString());
}
mInactivityTimers.remove(timer);
mInactivityTimerForRequest.remove(requestId);
return true;
}
return false;
}
public long getLingerExpiry() {
return mLingerExpiryMs;
public long getInactivityExpiry() {
return mInactivityExpiryMs;
}
public void updateLingerTimer() {
long newExpiry = mLingerTimers.isEmpty() ? 0 : mLingerTimers.last().expiryMs;
if (newExpiry == mLingerExpiryMs) return;
public void updateInactivityTimer() {
long newExpiry = mInactivityTimers.isEmpty() ? 0 : mInactivityTimers.last().expiryMs;
if (newExpiry == mInactivityExpiryMs) return;
// Even if we're going to reschedule the timer, cancel it first. This is because the
// semantics of WakeupMessage guarantee that if cancel is called then the alarm will
@@ -940,49 +943,52 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
// WakeupMessage makes no such guarantees about rescheduling a message, so if mLingerMessage
// has already been dispatched, rescheduling to some time in the future won't stop it
// from calling its callback immediately.
if (mLingerMessage != null) {
mLingerMessage.cancel();
mLingerMessage = null;
if (mInactivityMessage != null) {
mInactivityMessage.cancel();
mInactivityMessage = null;
}
if (newExpiry > 0) {
mLingerMessage = new WakeupMessage(
mInactivityMessage = new WakeupMessage(
mContext, mHandler,
"NETWORK_LINGER_COMPLETE." + network.getNetId() /* cmdName */,
EVENT_NETWORK_LINGER_COMPLETE /* cmd */,
0 /* arg1 (unused) */, 0 /* arg2 (unused) */,
this /* obj (NetworkAgentInfo) */);
mLingerMessage.schedule(newExpiry);
mInactivityMessage.schedule(newExpiry);
}
mLingerExpiryMs = newExpiry;
mInactivityExpiryMs = newExpiry;
}
public void linger() {
mLingering = true;
public void setInactive() {
mInactive = true;
}
public void unlinger() {
mLingering = false;
public void unsetInactive() {
mInactive = false;
}
public boolean isLingering() {
return mLingering;
return mInactive;
}
public void clearLingerState() {
if (mLingerMessage != null) {
mLingerMessage.cancel();
mLingerMessage = null;
public void clearInactivityState() {
if (mInactivityMessage != null) {
mInactivityMessage.cancel();
mInactivityMessage = null;
}
mLingerTimers.clear();
mLingerTimerForRequest.clear();
updateLingerTimer(); // Sets mLingerExpiryMs, cancels and nulls out mLingerMessage.
mLingering = false;
mInactivityTimers.clear();
mInactivityTimerForRequest.clear();
// Sets mInactivityExpiryMs, cancels and nulls out mInactivityMessage.
updateInactivityTimer();
mInactive = false;
}
public void dumpLingerTimers(PrintWriter pw) {
for (LingerTimer timer : mLingerTimers) { pw.println(timer); }
public void dumpInactivityTimers(PrintWriter pw) {
for (InactivityTimer timer : mInactivityTimers) {
pw.println(timer);
}
}
/**