Notify Vcn of VcnGatewayConnection quits
This change updates the Vcn when any GatewayConnection StateMachine quits, removing it from the map of active GatewayConnections, and triggering a re-evaluation of all existing NetworkRequests. This may (in the event of a updated policy) result in an immediate restart. Bug: 179944275 Test: atest FrameworksVcnTests Change-Id: I72abf1e270a772760a17a03173d5a110e15bd01d
This commit is contained in:
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.server.vcn;
|
||||
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
|
||||
|
||||
import static com.android.server.VcnManagementService.VDBG;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
@@ -84,6 +86,13 @@ public class Vcn extends Handler {
|
||||
*/
|
||||
private static final int MSG_EVENT_SUBSCRIPTIONS_CHANGED = MSG_EVENT_BASE + 2;
|
||||
|
||||
/**
|
||||
* A GatewayConnection owned by this VCN quit.
|
||||
*
|
||||
* @param obj VcnGatewayConnectionConfig
|
||||
*/
|
||||
private static final int MSG_EVENT_GATEWAY_CONNECTION_QUIT = MSG_EVENT_BASE + 3;
|
||||
|
||||
/** Triggers an immediate teardown of the entire Vcn, including GatewayConnections. */
|
||||
private static final int MSG_CMD_TEARDOWN = MSG_CMD_BASE;
|
||||
|
||||
@@ -208,6 +217,9 @@ public class Vcn extends Handler {
|
||||
case MSG_EVENT_SUBSCRIPTIONS_CHANGED:
|
||||
handleSubscriptionsChanged((TelephonySubscriptionSnapshot) msg.obj);
|
||||
break;
|
||||
case MSG_EVENT_GATEWAY_CONNECTION_QUIT:
|
||||
handleGatewayConnectionQuit((VcnGatewayConnectionConfig) msg.obj);
|
||||
break;
|
||||
case MSG_CMD_TEARDOWN:
|
||||
handleTeardown();
|
||||
break;
|
||||
@@ -263,7 +275,7 @@ public class Vcn extends Handler {
|
||||
|
||||
// If preexisting VcnGatewayConnection(s) satisfy request, return
|
||||
for (VcnGatewayConnectionConfig gatewayConnectionConfig : mVcnGatewayConnections.keySet()) {
|
||||
if (requestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
|
||||
if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
|
||||
if (VDBG) {
|
||||
Slog.v(
|
||||
getLogTag(),
|
||||
@@ -278,7 +290,7 @@ public class Vcn extends Handler {
|
||||
// up
|
||||
for (VcnGatewayConnectionConfig gatewayConnectionConfig :
|
||||
mConfig.getGatewayConnectionConfigs()) {
|
||||
if (requestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
|
||||
if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
|
||||
Slog.v(
|
||||
getLogTag(),
|
||||
"Bringing up new VcnGatewayConnection for request " + request.requestId);
|
||||
@@ -289,12 +301,21 @@ public class Vcn extends Handler {
|
||||
mSubscriptionGroup,
|
||||
mLastSnapshot,
|
||||
gatewayConnectionConfig,
|
||||
new VcnGatewayStatusCallbackImpl());
|
||||
new VcnGatewayStatusCallbackImpl(gatewayConnectionConfig));
|
||||
mVcnGatewayConnections.put(gatewayConnectionConfig, vcnGatewayConnection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleGatewayConnectionQuit(VcnGatewayConnectionConfig config) {
|
||||
Slog.v(getLogTag(), "VcnGatewayConnection quit: " + config);
|
||||
mVcnGatewayConnections.remove(config);
|
||||
|
||||
// Trigger a re-evaluation of all NetworkRequests (to make sure any that can be satisfied
|
||||
// start a new GatewayConnection)
|
||||
mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener);
|
||||
}
|
||||
|
||||
private void handleSubscriptionsChanged(@NonNull TelephonySubscriptionSnapshot snapshot) {
|
||||
mLastSnapshot = snapshot;
|
||||
|
||||
@@ -305,9 +326,10 @@ public class Vcn extends Handler {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean requestSatisfiedByGatewayConnectionConfig(
|
||||
private boolean isRequestSatisfiedByGatewayConnectionConfig(
|
||||
@NonNull NetworkRequest request, @NonNull VcnGatewayConnectionConfig config) {
|
||||
final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder();
|
||||
builder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
|
||||
for (int cap : config.getAllExposedCapabilities()) {
|
||||
builder.addCapability(cap);
|
||||
}
|
||||
@@ -339,9 +361,23 @@ public class Vcn extends Handler {
|
||||
@VcnErrorCode int errorCode,
|
||||
@Nullable String exceptionClass,
|
||||
@Nullable String exceptionMessage);
|
||||
|
||||
/** Called by a VcnGatewayConnection to indicate that it has fully torn down. */
|
||||
void onQuit();
|
||||
}
|
||||
|
||||
private class VcnGatewayStatusCallbackImpl implements VcnGatewayStatusCallback {
|
||||
public final VcnGatewayConnectionConfig mGatewayConnectionConfig;
|
||||
|
||||
VcnGatewayStatusCallbackImpl(VcnGatewayConnectionConfig gatewayConnectionConfig) {
|
||||
mGatewayConnectionConfig = gatewayConnectionConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQuit() {
|
||||
sendMessage(obtainMessage(MSG_EVENT_GATEWAY_CONNECTION_QUIT, mGatewayConnectionConfig));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnteredSafeMode() {
|
||||
sendMessage(obtainMessage(MSG_CMD_ENTER_SAFE_MODE));
|
||||
|
||||
@@ -649,6 +649,8 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
cancelSafeModeAlarm();
|
||||
|
||||
mUnderlyingNetworkTracker.teardown();
|
||||
|
||||
mGatewayStatusCallback.onQuit();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -67,9 +67,7 @@ public class VcnNetworkProvider extends NetworkProvider {
|
||||
mListeners.add(listener);
|
||||
|
||||
// Send listener all cached requests
|
||||
for (NetworkRequestEntry entry : mRequests.values()) {
|
||||
notifyListenerForEvent(listener, entry);
|
||||
}
|
||||
resendAllRequests(listener);
|
||||
}
|
||||
|
||||
/** Unregisters the specified listener from receiving future NetworkRequests. */
|
||||
@@ -78,6 +76,14 @@ public class VcnNetworkProvider extends NetworkProvider {
|
||||
mListeners.remove(listener);
|
||||
}
|
||||
|
||||
/** Sends all cached NetworkRequest(s) to the specified listener. */
|
||||
@VisibleForTesting(visibility = Visibility.PACKAGE)
|
||||
public void resendAllRequests(@NonNull NetworkRequestListener listener) {
|
||||
for (NetworkRequestEntry entry : mRequests.values()) {
|
||||
notifyListenerForEvent(listener, entry);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyListenerForEvent(
|
||||
@NonNull NetworkRequestListener listener, @NonNull NetworkRequestEntry entry) {
|
||||
listener.onNetworkRequested(entry.mRequest, entry.mScore, entry.mProviderId);
|
||||
|
||||
@@ -26,6 +26,7 @@ import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.net.IpSecManager;
|
||||
@@ -104,6 +105,7 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect
|
||||
verify(mIpSecSvc).deleteTunnelInterface(eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), any());
|
||||
verifySafeModeTimeoutAlarmAndGetCallback(true /* expectCanceled */);
|
||||
assertFalse(mGatewayConnection.isRunning());
|
||||
verify(mGatewayStatusCallback).onQuit();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -113,6 +115,7 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect
|
||||
|
||||
assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState());
|
||||
assertTrue(mGatewayConnection.isRunning());
|
||||
verify(mGatewayStatusCallback, never()).onQuit();
|
||||
// No safe mode timer changes expected.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
|
||||
package com.android.server.vcn;
|
||||
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.mockito.Matchers.any;
|
||||
@@ -33,6 +37,7 @@ import android.net.vcn.VcnGatewayConnectionConfig;
|
||||
import android.net.vcn.VcnGatewayConnectionConfigTest;
|
||||
import android.os.ParcelUuid;
|
||||
import android.os.test.TestLooper;
|
||||
import android.util.ArraySet;
|
||||
|
||||
import com.android.server.VcnManagementService.VcnCallback;
|
||||
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
|
||||
@@ -51,6 +56,11 @@ public class VcnTest {
|
||||
private static final ParcelUuid TEST_SUB_GROUP = new ParcelUuid(new UUID(0, 0));
|
||||
private static final int NETWORK_SCORE = 0;
|
||||
private static final int PROVIDER_ID = 5;
|
||||
private static final int[][] TEST_CAPS =
|
||||
new int[][] {
|
||||
new int[] {NET_CAPABILITY_INTERNET, NET_CAPABILITY_MMS},
|
||||
new int[] {NET_CAPABILITY_DUN}
|
||||
};
|
||||
|
||||
private Context mContext;
|
||||
private VcnContext mVcnContext;
|
||||
@@ -91,13 +101,12 @@ public class VcnTest {
|
||||
mGatewayStatusCallbackCaptor = ArgumentCaptor.forClass(VcnGatewayStatusCallback.class);
|
||||
|
||||
final VcnConfig.Builder configBuilder = new VcnConfig.Builder(mContext);
|
||||
for (final int capability : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) {
|
||||
for (final int[] caps : TEST_CAPS) {
|
||||
configBuilder.addGatewayConnectionConfig(
|
||||
VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(capability));
|
||||
VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(caps));
|
||||
}
|
||||
configBuilder.addGatewayConnectionConfig(VcnGatewayConnectionConfigTest.buildTestConfig());
|
||||
mConfig = configBuilder.build();
|
||||
|
||||
mConfig = configBuilder.build();
|
||||
mVcn =
|
||||
new Vcn(
|
||||
mVcnContext,
|
||||
@@ -130,8 +139,7 @@ public class VcnTest {
|
||||
@Test
|
||||
public void testSubscriptionSnapshotUpdatesVcnGatewayConnections() {
|
||||
final NetworkRequestListener requestListener = verifyAndGetRequestListener();
|
||||
startVcnGatewayWithCapabilities(
|
||||
requestListener, VcnGatewayConnectionConfigTest.EXPOSED_CAPS);
|
||||
startVcnGatewayWithCapabilities(requestListener, TEST_CAPS[0]);
|
||||
|
||||
final Set<VcnGatewayConnection> gatewayConnections = mVcn.getVcnGatewayConnections();
|
||||
assertFalse(gatewayConnections.isEmpty());
|
||||
@@ -153,10 +161,19 @@ public class VcnTest {
|
||||
for (final int capability : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) {
|
||||
startVcnGatewayWithCapabilities(requestListener, capability);
|
||||
}
|
||||
}
|
||||
|
||||
// Each Capability in EXPOSED_CAPS was split into a separate VcnGatewayConnection in #setUp.
|
||||
// Expect one VcnGatewayConnection per capability.
|
||||
final int numExpectedGateways = VcnGatewayConnectionConfigTest.EXPOSED_CAPS.length;
|
||||
private void triggerVcnRequestListeners(NetworkRequestListener requestListener) {
|
||||
for (final int[] caps : TEST_CAPS) {
|
||||
startVcnGatewayWithCapabilities(requestListener, caps);
|
||||
}
|
||||
}
|
||||
|
||||
public Set<VcnGatewayConnection> startGatewaysAndGetGatewayConnections(
|
||||
NetworkRequestListener requestListener) {
|
||||
triggerVcnRequestListeners(requestListener);
|
||||
|
||||
final int numExpectedGateways = TEST_CAPS.length;
|
||||
|
||||
final Set<VcnGatewayConnection> gatewayConnections = mVcn.getVcnGatewayConnections();
|
||||
assertEquals(numExpectedGateways, gatewayConnections.size());
|
||||
@@ -168,7 +185,16 @@ public class VcnTest {
|
||||
any(),
|
||||
mGatewayStatusCallbackCaptor.capture());
|
||||
|
||||
// Doesn't matter which callback this gets - any Gateway entering safe mode should shut down
|
||||
return gatewayConnections;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGatewayEnteringSafemodeNotifiesVcn() {
|
||||
final NetworkRequestListener requestListener = verifyAndGetRequestListener();
|
||||
final Set<VcnGatewayConnection> gatewayConnections =
|
||||
startGatewaysAndGetGatewayConnections(requestListener);
|
||||
|
||||
// Doesn't matter which callback this gets - any Gateway entering Safemode should shut down
|
||||
// all Gateways
|
||||
final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue();
|
||||
statusCallback.onEnteredSafeMode();
|
||||
@@ -181,4 +207,31 @@ public class VcnTest {
|
||||
verify(mVcnNetworkProvider).unregisterListener(requestListener);
|
||||
verify(mVcnCallback).onEnteredSafeMode();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGatewayQuit() {
|
||||
final NetworkRequestListener requestListener = verifyAndGetRequestListener();
|
||||
final Set<VcnGatewayConnection> gatewayConnections =
|
||||
new ArraySet<>(startGatewaysAndGetGatewayConnections(requestListener));
|
||||
|
||||
final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue();
|
||||
statusCallback.onQuit();
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
// Verify that the VCN requests the networkRequests be resent
|
||||
assertEquals(1, mVcn.getVcnGatewayConnections().size());
|
||||
verify(mVcnNetworkProvider).resendAllRequests(requestListener);
|
||||
|
||||
// Verify that the VcnGatewayConnection is restarted
|
||||
triggerVcnRequestListeners(requestListener);
|
||||
mTestLooper.dispatchAll();
|
||||
assertEquals(2, mVcn.getVcnGatewayConnections().size());
|
||||
verify(mDeps, times(gatewayConnections.size() + 1))
|
||||
.newVcnGatewayConnection(
|
||||
eq(mVcnContext),
|
||||
eq(TEST_SUB_GROUP),
|
||||
eq(mSubscriptionSnapshot),
|
||||
any(),
|
||||
mGatewayStatusCallbackCaptor.capture());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user