diff options
author | Benedict Wong <benedictwong@google.com> | 2021-02-10 15:44:26 -0800 |
---|---|---|
committer | Benedict Wong <benedictwong@google.com> | 2021-03-01 15:36:24 -0800 |
commit | 75a32b9401ffdf4089deb86c15b4337d58660ae7 (patch) | |
tree | 118200a7fd4de8f2a8039cb7fbd9085901633ff1 | |
parent | b7cc3c61066e5019e79a3b7dc80d0193e39f23de (diff) |
Allow NETWORK_LOST disconnections to retry
This change adds the ability for disconnection requests to specify
whether the full VcnGatewayConnection should be torn down. This is
useful in cases where the cause is an ephemeral failure, and can be
restarted at some later point (eg an underlying network appears, or a
new NetworkRequest is filed that brings the VCN up.)
Bug: 179944275
Test: atest FrameworksVcnTests
Change-Id: Id1813bcbbb80541be97cc383ea9d1fe08554b7ae
6 files changed, 126 insertions, 34 deletions
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java index 06748a3aa2d1..a2f4782ec1e8 100644 --- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java +++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java @@ -168,6 +168,8 @@ public class VcnGatewayConnection extends StateMachine { private static final String DISCONNECT_REASON_INTERNAL_ERROR = "Uncaught exception: "; private static final String DISCONNECT_REASON_UNDERLYING_NETWORK_LOST = "Underlying Network lost"; + private static final String DISCONNECT_REASON_NETWORK_AGENT_UNWANTED = + "NetworkAgent was unwanted"; private static final String DISCONNECT_REASON_TEARDOWN = "teardown() called on VcnTunnel"; private static final int TOKEN_ALL = Integer.MIN_VALUE; @@ -379,13 +381,16 @@ public class VcnGatewayConnection extends StateMachine { /** The reason why the disconnect was requested. */ @NonNull public final String reason; - EventDisconnectRequestedInfo(@NonNull String reason) { + public final boolean shouldTeardown; + + EventDisconnectRequestedInfo(@NonNull String reason, boolean shouldTeardown) { this.reason = Objects.requireNonNull(reason); + this.shouldTeardown = shouldTeardown; } @Override public int hashCode() { - return Objects.hash(reason); + return Objects.hash(reason, shouldTeardown); } @Override @@ -395,7 +400,7 @@ public class VcnGatewayConnection extends StateMachine { } final EventDisconnectRequestedInfo rhs = (EventDisconnectRequestedInfo) other; - return reason.equals(rhs.reason); + return reason.equals(rhs.reason) && shouldTeardown == rhs.shouldTeardown; } } @@ -622,10 +627,8 @@ public class VcnGatewayConnection extends StateMachine { * <p>Once torn down, this VcnTunnel CANNOT be started again. */ public void teardownAsynchronously() { - sendMessageAndAcquireWakeLock( - EVENT_DISCONNECT_REQUESTED, - TOKEN_ALL, - new EventDisconnectRequestedInfo(DISCONNECT_REASON_TEARDOWN)); + sendDisconnectRequestedAndAcquireWakelock( + DISCONNECT_REASON_TEARDOWN, true /* shouldTeardown */); // TODO: Notify VcnInstance (via callbacks) of permanent teardown of this tunnel, since this // is also called asynchronously when a NetworkAgent becomes unwanted @@ -892,7 +895,8 @@ public class VcnGatewayConnection extends StateMachine { TOKEN_ALL, 0 /* arg2 */, new EventDisconnectRequestedInfo( - DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)); + DISCONNECT_REASON_UNDERLYING_NETWORK_LOST, + false /* shouldTeardown */)); mDisconnectRequestAlarm = createScheduledAlarm( DISCONNECT_REQUEST_ALARM, @@ -909,7 +913,8 @@ public class VcnGatewayConnection extends StateMachine { // Cancel any existing disconnect due to previous loss of underlying network removeEqualMessages( EVENT_DISCONNECT_REQUESTED, - new EventDisconnectRequestedInfo(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)); + new EventDisconnectRequestedInfo( + DISCONNECT_REASON_UNDERLYING_NETWORK_LOST, false /* shouldTeardown */)); } private void setRetryTimeoutAlarm(long delay) { @@ -1041,11 +1046,8 @@ public class VcnGatewayConnection extends StateMachine { enterState(); } catch (Exception e) { Slog.wtf(TAG, "Uncaught exception", e); - sendMessageAndAcquireWakeLock( - EVENT_DISCONNECT_REQUESTED, - TOKEN_ALL, - new EventDisconnectRequestedInfo( - DISCONNECT_REASON_INTERNAL_ERROR + e.toString())); + sendDisconnectRequestedAndAcquireWakelock( + DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldTeardown */); } } @@ -1083,11 +1085,8 @@ public class VcnGatewayConnection extends StateMachine { processStateMsg(msg); } catch (Exception e) { Slog.wtf(TAG, "Uncaught exception", e); - sendMessageAndAcquireWakeLock( - EVENT_DISCONNECT_REQUESTED, - TOKEN_ALL, - new EventDisconnectRequestedInfo( - DISCONNECT_REASON_INTERNAL_ERROR + e.toString())); + sendDisconnectRequestedAndAcquireWakelock( + DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldTeardown */); } // Attempt to release the WakeLock - only possible if the Handler queue is empty @@ -1104,11 +1103,8 @@ public class VcnGatewayConnection extends StateMachine { exitState(); } catch (Exception e) { Slog.wtf(TAG, "Uncaught exception", e); - sendMessageAndAcquireWakeLock( - EVENT_DISCONNECT_REQUESTED, - TOKEN_ALL, - new EventDisconnectRequestedInfo( - DISCONNECT_REASON_INTERNAL_ERROR + e.toString())); + sendDisconnectRequestedAndAcquireWakelock( + DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldTeardown */); } } @@ -1141,11 +1137,11 @@ public class VcnGatewayConnection extends StateMachine { } } - protected void handleDisconnectRequested(String msg) { + protected void handleDisconnectRequested(EventDisconnectRequestedInfo info) { // TODO(b/180526152): notify VcnStatusCallback for Network loss - Slog.v(TAG, "Tearing down. Cause: " + msg); - mIsRunning = false; + Slog.v(TAG, "Tearing down. Cause: " + info.reason); + mIsRunning = !info.shouldTeardown; teardownNetwork(); @@ -1200,9 +1196,11 @@ public class VcnGatewayConnection extends StateMachine { } break; case EVENT_DISCONNECT_REQUESTED: - mIsRunning = false; + if (((EventDisconnectRequestedInfo) msg.obj).shouldTeardown) { + mIsRunning = false; - quitNow(); + quitNow(); + } break; default: logUnhandledMessage(msg); @@ -1284,10 +1282,11 @@ public class VcnGatewayConnection extends StateMachine { break; case EVENT_DISCONNECT_REQUESTED: + EventDisconnectRequestedInfo info = ((EventDisconnectRequestedInfo) msg.obj); + mIsRunning = !info.shouldTeardown; teardownNetwork(); - String reason = ((EventDisconnectRequestedInfo) msg.obj).reason; - if (reason.equals(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)) { + if (info.reason.equals(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)) { // TODO(b/180526152): notify VcnStatusCallback for Network loss // Will trigger EVENT_SESSION_CLOSED immediately. @@ -1391,7 +1390,7 @@ public class VcnGatewayConnection extends StateMachine { transitionTo(mConnectedState); break; case EVENT_DISCONNECT_REQUESTED: - handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason); + handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj); break; case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED: mGatewayStatusCallback.onEnteredSafeMode(); @@ -1438,6 +1437,7 @@ public class VcnGatewayConnection extends StateMachine { mVcnContext.getVcnNetworkProvider()) { @Override public void unwanted() { + Slog.d(TAG, "NetworkAgent was unwanted"); teardownAsynchronously(); } @@ -1577,7 +1577,7 @@ public class VcnGatewayConnection extends StateMachine { setupInterfaceAndNetworkAgent(mCurrentToken, mTunnelIface, mChildConfig); break; case EVENT_DISCONNECT_REQUESTED: - handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason); + handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj); break; case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED: mGatewayStatusCallback.onEnteredSafeMode(); @@ -1682,7 +1682,7 @@ public class VcnGatewayConnection extends StateMachine { transitionTo(mConnectingState); break; case EVENT_DISCONNECT_REQUESTED: - handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason); + handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj); break; case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED: mGatewayStatusCallback.onEnteredSafeMode(); @@ -1924,6 +1924,14 @@ public class VcnGatewayConnection extends StateMachine { mIkeSession = session; } + @VisibleForTesting(visibility = Visibility.PRIVATE) + void sendDisconnectRequestedAndAcquireWakelock(String reason, boolean shouldTeardown) { + sendMessageAndAcquireWakeLock( + EVENT_DISCONNECT_REQUESTED, + TOKEN_ALL, + new EventDisconnectRequestedInfo(reason, shouldTeardown)); + } + private IkeSessionParams buildIkeParams() { // TODO: Implement this once IkeSessionParams is persisted return null; diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 69c21b967917..12c61cec8718 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -290,4 +290,22 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection verifyIkeSessionClosedExceptionalltyNotifiesStatusCallback( new TemporaryFailureException("vcn test"), VCN_ERROR_CODE_INTERNAL_ERROR); } + + @Test + public void testTeardown() throws Exception { + mGatewayConnection.teardownAsynchronously(); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); + assertFalse(mGatewayConnection.isRunning()); + } + + @Test + public void testNonTeardownDisconnectRequest() throws Exception { + mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); + assertTrue(mGatewayConnection.isRunning()); + } } diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java index 17ae19e086cf..0f94426e1213 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java @@ -19,6 +19,8 @@ package com.android.server.vcn; import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -111,4 +113,22 @@ public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectio public void testSafeModeTimeoutNotifiesCallback() { verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mConnectingState); } + + @Test + public void testTeardown() throws Exception { + mGatewayConnection.teardownAsynchronously(); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); + assertFalse(mGatewayConnection.isRunning()); + } + + @Test + public void testNonTeardownDisconnectRequest() throws Exception { + mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); + assertTrue(mGatewayConnection.isRunning()); + } } diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java index 9ea641f52e48..90810b6cd4f4 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java @@ -21,7 +21,9 @@ import static android.net.IpSecManager.IpSecTunnelInterface; import static com.android.server.vcn.VcnGatewayConnection.DUMMY_ADDR; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; 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.verify; @@ -101,5 +103,16 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect assertNull(mGatewayConnection.getCurrentState()); verify(mIpSecSvc).deleteTunnelInterface(eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), any()); verifySafeModeTimeoutAlarmAndGetCallback(true /* expectCanceled */); + assertFalse(mGatewayConnection.isRunning()); + } + + @Test + public void testNonTeardownDisconnectRequest() throws Exception { + mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState()); + assertTrue(mGatewayConnection.isRunning()); + // No safe mode timer changes expected. } } diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java index 7385204993c0..c57237c2f7f0 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java @@ -18,6 +18,8 @@ package com.android.server.vcn; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -79,10 +81,20 @@ public class VcnGatewayConnectionDisconnectingStateTest extends VcnGatewayConnec // Should do nothing; already tearing down. assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */); + assertFalse(mGatewayConnection.isRunning()); } @Test public void testSafeModeTimeoutNotifiesCallback() { verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mDisconnectingState); } + + @Test + public void testNonTeardownDisconnectRequest() throws Exception { + mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); + assertTrue(mGatewayConnection.isRunning()); + } } diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java index 5b0850b03f1a..1e8e7a0b772c 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java @@ -17,6 +17,9 @@ package com.android.server.vcn; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -96,4 +99,22 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect public void testSafeModeTimeoutNotifiesCallback() { verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mRetryTimeoutState); } + + @Test + public void testTeardownDisconnectRequest() throws Exception { + mGatewayConnection.teardownAsynchronously(); + mTestLooper.dispatchAll(); + + assertNull(mGatewayConnection.getCurrentState()); + assertFalse(mGatewayConnection.isRunning()); + } + + @Test + public void testNonTeardownDisconnectRequest() throws Exception { + mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState()); + assertTrue(mGatewayConnection.isRunning()); + } } |