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.println(nai.requestAt(i).toString());
} }
pw.decreaseIndent(); pw.decreaseIndent();
pw.println("Lingered:"); pw.println("Inactivity Timers:");
pw.increaseIndent(); pw.increaseIndent();
nai.dumpLingerTimers(pw); nai.dumpInactivityTimers(pw);
pw.decreaseIndent(); pw.decreaseIndent();
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 nai the agent info to update
* @param now the timestamp of the event causing this 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) { private boolean updateInactivityState(@NonNull final NetworkAgentInfo nai, final long now) {
// 1. Update the linger timer. If it's changed, reschedule or cancel the alarm. // 1. Update the inactivity timer. If it's changed, reschedule or cancel the alarm.
// 2. If the network was lingering and there are now requests, unlinger it. // 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 // 3. If this network is unneeded (which implies it is not lingering), and there is at least
// one lingered request, start lingering. // one lingered request, set inactive.
nai.updateLingerTimer(); nai.updateInactivityTimer();
if (nai.isLingering() && nai.numForegroundNetworkRequests() > 0) { if (nai.isLingering() && nai.numForegroundNetworkRequests() > 0) {
if (DBG) log("Unlingering " + nai.toShortString()); if (DBG) log("Unsetting inactive " + nai.toShortString());
nai.unlinger(); nai.unsetInactive();
logNetworkEvent(nai, NetworkEvent.NETWORK_UNLINGER); 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) { if (DBG) {
final int lingerTime = (int) (nai.getLingerExpiry() - now); final int lingerTime = (int) (nai.getInactivityExpiry() - now);
log("Lingering " + nai.toShortString() + " for " + lingerTime + "ms"); log("Setting inactive " + nai.toShortString() + " for " + lingerTime + "ms");
} }
nai.linger(); nai.setInactive();
logNetworkEvent(nai, NetworkEvent.NETWORK_LINGER); logNetworkEvent(nai, NetworkEvent.NETWORK_LINGER);
return true; 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. // 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. // Currently, deleting it breaks tests that check for the default network disconnecting.
// Find out why, fix the rematch code, and delete this. // 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, // If there are still lingered requests on this network, don't tear it down,
// but resume lingering instead. // but resume lingering instead.
final long now = SystemClock.elapsedRealtime(); final long now = SystemClock.elapsedRealtime();
if (updateLingerState(nai, now)) { if (updateInactivityState(nai, now)) {
notifyNetworkLosing(nai, now); notifyNetworkLosing(nai, now);
} }
if (unneeded(nai, UnneededFor.TEARDOWN)) { 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 // 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. // must be no other active linger timers, and we must stop lingering.
oldNetwork.clearLingerState(); oldNetwork.clearInactivityState();
if (unneeded(oldNetwork, UnneededFor.TEARDOWN)) { if (unneeded(oldNetwork, UnneededFor.TEARDOWN)) {
// Tear the network down. // 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 // if the state has not changed : the source of truth is controlled with
// NetworkAgentInfo#lingerRequest and NetworkAgentInfo#unlingerRequest, which have been // NetworkAgentInfo#lingerRequest and NetworkAgentInfo#unlingerRequest, which have been
// called while rematching the individual networks above. // called while rematching the individual networks above.
if (updateLingerState(nai, now)) { if (updateInactivityState(nai, now)) {
lingeredNetworks.add(nai); lingeredNetworks.add(nai);
} }
} }
@@ -7678,7 +7678,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Tear down all unneeded networks. // Tear down all unneeded networks.
for (NetworkAgentInfo nai : mNetworkAgentInfos) { for (NetworkAgentInfo nai : mNetworkAgentInfos) {
if (unneeded(nai, UnneededFor.TEARDOWN)) { 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 // This network has active linger timers and no requests, but is not
// lingering. Linger it. // 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 // 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 // point where this network will no longer be able to satisfy any requests
// even if it validates. // even if it validates.
if (updateLingerState(nai, now)) { if (updateInactivityState(nai, now)) {
notifyNetworkLosing(nai, now); notifyNetworkLosing(nai, now);
} }
} else { } else {
@@ -7963,7 +7963,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Notify the requests on this NAI that the network is now lingered. // Notify the requests on this NAI that the network is now lingered.
private void notifyNetworkLosing(@NonNull final NetworkAgentInfo nai, final long now) { 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); 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 // 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 // either the linger timeout expiring and the network being taken down, or the network
// satisfying a request again. // satisfying a request again.
public static class LingerTimer implements Comparable<LingerTimer> { public static class InactivityTimer implements Comparable<InactivityTimer> {
public final int requestId; public final int requestId;
public final long expiryMs; public final long expiryMs;
public LingerTimer(int requestId, long expiryMs) { public InactivityTimer(int requestId, long expiryMs) {
this.requestId = requestId; this.requestId = requestId;
this.expiryMs = expiryMs; this.expiryMs = expiryMs;
} }
public boolean equals(Object o) { public boolean equals(Object o) {
if (!(o instanceof LingerTimer)) return false; if (!(o instanceof InactivityTimer)) return false;
LingerTimer other = (LingerTimer) o; InactivityTimer other = (InactivityTimer) o;
return (requestId == other.requestId) && (expiryMs == other.expiryMs); return (requestId == other.requestId) && (expiryMs == other.expiryMs);
} }
public int hashCode() { public int hashCode() {
return Objects.hash(requestId, expiryMs); return Objects.hash(requestId, expiryMs);
} }
public int compareTo(LingerTimer other) { public int compareTo(InactivityTimer other) {
return (expiryMs != other.expiryMs) ? return (expiryMs != other.expiryMs) ?
Long.compare(expiryMs, other.expiryMs) : Long.compare(expiryMs, other.expiryMs) :
Integer.compare(requestId, other.requestId); Integer.compare(requestId, other.requestId);
@@ -269,30 +269,31 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
*/ */
public static final int ARG_AGENT_SUCCESS = 1; 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 // a request is moved to a network with a better score, regardless of whether the network is or
// was lingering or not. // was lingering or not.
// TODO: determine if we can replace this with a smaller or unsorted data structure. (e.g., // 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. // 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. // For fast lookups. Indexes into mInactivityTimers by request ID.
private final SparseArray<LingerTimer> mLingerTimerForRequest = new SparseArray<>(); private final SparseArray<InactivityTimer> mInactivityTimerForRequest = new SparseArray<>();
// Linger expiry timer. Armed whenever mLingerTimers is non-empty, regardless of whether the // Inactivity expiry timer. Armed whenever mInactivityTimers is non-empty, regardless of
// network is lingering or not. Always set to the expiry of the LingerTimer that expires last. // whether the network is inactive or not. Always set to the expiry of the mInactivityTimers
// When the timer fires, all linger state is cleared, and if the network has no requests, it is // that expires last. When the timer fires, all inactivity state is cleared, and if the network
// torn down. // has no requests, it is torn down.
private WakeupMessage mLingerMessage; private WakeupMessage mInactivityMessage;
// Linger expiry. Holds the expiry time of the linger timer, or 0 if the timer is not armed. // Inactivity expiry. Holds the expiry time of the inactivity timer, or 0 if the timer is not
private long mLingerExpiryMs; // 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. // 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 // (Example: we don't linger a network if it would become the best for a NetworkRequest if it
// validated). // validated).
private boolean mLingering; private boolean mInactive;
// This represents the quality of the network with no clear scale. // This represents the quality of the network with no clear scale.
private int mScore; 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. * ConnectivityService when the request is moved to another network with a higher score.
*/ */
public void lingerRequest(int requestId, long now, long duration) { 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 // 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 // re-linger it unless that network becomes the best for that request again, in which
// case we should have unlingered it. // case we should have unlingered it.
Log.wtf(TAG, toShortString() + ": request " + requestId + " already lingered"); Log.wtf(TAG, toShortString() + ": request " + requestId + " already lingered");
} }
final long expiryMs = now + duration; final long expiryMs = now + duration;
LingerTimer timer = new LingerTimer(requestId, expiryMs); InactivityTimer timer = new InactivityTimer(requestId, expiryMs);
if (VDBG) Log.d(TAG, "Adding LingerTimer " + timer + " to " + toShortString()); if (VDBG) Log.d(TAG, "Adding InactivityTimer " + timer + " to " + toShortString());
mLingerTimers.add(timer); mInactivityTimers.add(timer);
mLingerTimerForRequest.put(requestId, 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. * Returns true if the given requestId was lingering on this network, false otherwise.
*/ */
public boolean unlingerRequest(int requestId) { public boolean unlingerRequest(int requestId) {
LingerTimer timer = mLingerTimerForRequest.get(requestId); InactivityTimer timer = mInactivityTimerForRequest.get(requestId);
if (timer != null) { if (timer != null) {
if (VDBG) Log.d(TAG, "Removing LingerTimer " + timer + " from " + toShortString()); if (VDBG) {
mLingerTimers.remove(timer); Log.d(TAG, "Removing InactivityTimer " + timer + " from " + toShortString());
mLingerTimerForRequest.remove(requestId); }
mInactivityTimers.remove(timer);
mInactivityTimerForRequest.remove(requestId);
return true; return true;
} }
return false; return false;
} }
public long getLingerExpiry() { public long getInactivityExpiry() {
return mLingerExpiryMs; return mInactivityExpiryMs;
} }
public void updateLingerTimer() { public void updateInactivityTimer() {
long newExpiry = mLingerTimers.isEmpty() ? 0 : mLingerTimers.last().expiryMs; long newExpiry = mInactivityTimers.isEmpty() ? 0 : mInactivityTimers.last().expiryMs;
if (newExpiry == mLingerExpiryMs) return; if (newExpiry == mInactivityExpiryMs) return;
// Even if we're going to reschedule the timer, cancel it first. This is because the // 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 // 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 // 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 // has already been dispatched, rescheduling to some time in the future won't stop it
// from calling its callback immediately. // from calling its callback immediately.
if (mLingerMessage != null) { if (mInactivityMessage != null) {
mLingerMessage.cancel(); mInactivityMessage.cancel();
mLingerMessage = null; mInactivityMessage = null;
} }
if (newExpiry > 0) { if (newExpiry > 0) {
mLingerMessage = new WakeupMessage( mInactivityMessage = new WakeupMessage(
mContext, mHandler, mContext, mHandler,
"NETWORK_LINGER_COMPLETE." + network.getNetId() /* cmdName */, "NETWORK_LINGER_COMPLETE." + network.getNetId() /* cmdName */,
EVENT_NETWORK_LINGER_COMPLETE /* cmd */, EVENT_NETWORK_LINGER_COMPLETE /* cmd */,
0 /* arg1 (unused) */, 0 /* arg2 (unused) */, 0 /* arg1 (unused) */, 0 /* arg2 (unused) */,
this /* obj (NetworkAgentInfo) */); this /* obj (NetworkAgentInfo) */);
mLingerMessage.schedule(newExpiry); mInactivityMessage.schedule(newExpiry);
} }
mLingerExpiryMs = newExpiry; mInactivityExpiryMs = newExpiry;
} }
public void linger() { public void setInactive() {
mLingering = true; mInactive = true;
} }
public void unlinger() { public void unsetInactive() {
mLingering = false; mInactive = false;
} }
public boolean isLingering() { public boolean isLingering() {
return mLingering; return mInactive;
} }
public void clearLingerState() { public void clearInactivityState() {
if (mLingerMessage != null) { if (mInactivityMessage != null) {
mLingerMessage.cancel(); mInactivityMessage.cancel();
mLingerMessage = null; mInactivityMessage = null;
} }
mLingerTimers.clear(); mInactivityTimers.clear();
mLingerTimerForRequest.clear(); mInactivityTimerForRequest.clear();
updateLingerTimer(); // Sets mLingerExpiryMs, cancels and nulls out mLingerMessage. // Sets mInactivityExpiryMs, cancels and nulls out mInactivityMessage.
mLingering = false; updateInactivityTimer();
mInactive = false;
} }
public void dumpLingerTimers(PrintWriter pw) { public void dumpInactivityTimers(PrintWriter pw) {
for (LingerTimer timer : mLingerTimers) { pw.println(timer); } for (InactivityTimer timer : mInactivityTimers) {
pw.println(timer);
}
} }
/** /**