Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fb2c686f authored by Junyu Lai's avatar Junyu Lai Committed by Gerrit Code Review
Browse files

Merge "[VCN09] Rename linger timer"

parents ec30b110 0452d4a2
Loading
Loading
Loading
Loading
+22 −22
Original line number Diff line number Diff line
@@ -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);
    }

+59 −53
Original line number Diff line number Diff line
@@ -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);
        }
    }

    /**