From bf91f5f182b9a3d54e40ff3b1848a40d2c1f257f Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 3 Dec 2019 22:16:26 +0900 Subject: [PATCH] [NS A37] Don't reassign requests multiple times This is an optimization that skips doing intermediate assignments of networks to requests that will undergo multiple changes during the recomputation. It happens to fix a bug where some of these intermediate states used to have a visible, transient side effect. Bug: 113554781 Test: ConnectivityServiceTest Change-Id: I7af3728152a1cf7571de67f394088a5970ee3c1e --- .../android/server/ConnectivityService.java | 32 +++++++++++++------ .../server/ConnectivityServiceTest.java | 8 ++--- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 0e17b23249..25e34e2786 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -6452,18 +6452,37 @@ public class ConnectivityService extends IConnectivityManager.Stub } @NonNull private final Set mRematchedNetworks = new ArraySet<>(); - @NonNull private final List mReassignments = new ArrayList<>(); + @NonNull private final Map mReassignments = + new ArrayMap<>(); @NonNull Iterable getRematchedNetworks() { return mRematchedNetworks; } @NonNull Iterable getRequestReassignments() { - return mReassignments; + return mReassignments.values(); } void addRequestReassignment(@NonNull final RequestReassignment reassignment) { - mReassignments.add(reassignment); + final RequestReassignment oldChange = mReassignments.get(reassignment.mRequest); + if (null == oldChange) { + mReassignments.put(reassignment.mRequest, reassignment); + return; + } + if (oldChange.mNewNetwork != reassignment.mOldNetwork) { + throw new IllegalArgumentException("Reassignment <" + reassignment.mRequest + "> [" + + reassignment.mOldNetwork + " -> " + reassignment.mNewNetwork + + "] conflicts with [" + + oldChange.mOldNetwork + " -> " + oldChange.mNewNetwork + "]"); + } + // There was already a note to reassign this request from a network A to a network B, + // and a reassignment is added from network B to some other network C. The following + // synthesizes the merged reassignment that goes A -> C. An interesting (but not + // special) case to think about is when B is null, which can happen when the rematch + // loop notices the current satisfier doesn't satisfy the request any more, but + // hasn't yet encountered another network that could. + mReassignments.put(reassignment.mRequest, new RequestReassignment(reassignment.mRequest, + oldChange.mOldNetwork, reassignment.mNewNetwork)); } void addRematchedNetwork(@NonNull final NetworkBgStatePair network) { @@ -6653,13 +6672,6 @@ public class ConnectivityService extends IConnectivityManager.Stub if (null != event.mNewNetwork) { notifyNetworkAvailable(event.mNewNetwork, event.mRequest); } else { - // TODO: Technically, sending CALLBACK_LOST here is - // incorrect if there is a replacement network currently - // connected that can satisfy nri, which is a request - // (not a listen). However, the only capability that can both - // a) be requested and b) change is NET_CAPABILITY_TRUSTED, - // so this code is only incorrect for a network that loses - // the TRUSTED capability, which is a rare case. callCallbackForRequest(event.mRequest, event.mOldNetwork, ConnectivityManager.CALLBACK_LOST, 0); } diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 1442b31aa8..072d336bc6 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -5753,20 +5753,18 @@ public class ConnectivityServiceTest { mCellNetworkAgent.connect(true); trustedCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); verify(mNetworkManagementService).setDefaultNetId(eq(mCellNetworkAgent.getNetwork().netId)); + reset(mNetworkManagementService); mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); trustedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); verify(mNetworkManagementService).setDefaultNetId(eq(mWiFiNetworkAgent.getNetwork().netId)); + reset(mNetworkManagementService); mWiFiNetworkAgent.removeCapability(NET_CAPABILITY_TRUSTED); - // There is currently a bug where losing the TRUSTED capability will send a LOST - // callback to requests before the available callback, in spite of the semantics - // of the requests dictating this should not happen. This is considered benign, but - // ideally should be fixed in the future. - trustedCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent); trustedCallback.expectAvailableCallbacksValidated(mCellNetworkAgent); verify(mNetworkManagementService).setDefaultNetId(eq(mCellNetworkAgent.getNetwork().netId)); + reset(mNetworkManagementService); mCellNetworkAgent.removeCapability(NET_CAPABILITY_TRUSTED); trustedCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);