Merge "Implement DisconnectingState" am: 2cfb250d6d
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1547274 MUST ONLY BE SUBMITTED BY AUTOMERGER Change-Id: I265cfe4d4cd4a2b8f13bd18e71baf7d18e144d03
This commit is contained in:
@@ -122,7 +122,9 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
private static final int TOKEN_ALL = Integer.MIN_VALUE;
|
||||
|
||||
private static final int NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS = 30;
|
||||
private static final int TEARDOWN_TIMEOUT_SECONDS = 5;
|
||||
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
static final int TEARDOWN_TIMEOUT_SECONDS = 5;
|
||||
|
||||
private interface EventInfo {}
|
||||
|
||||
@@ -412,13 +414,6 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
*/
|
||||
private int mCurrentToken = -1;
|
||||
|
||||
/**
|
||||
* The next usable token.
|
||||
*
|
||||
* <p>A new token MUST be used for all new IKE sessions.
|
||||
*/
|
||||
private int mNextToken = 0;
|
||||
|
||||
/**
|
||||
* The number of unsuccessful attempts since the last successful connection.
|
||||
*
|
||||
@@ -440,7 +435,7 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
* <p>Set in Connecting or Migrating States, always @NonNull in Connecting, Connected, and
|
||||
* Migrating states, null otherwise.
|
||||
*/
|
||||
private IkeSession mIkeSession;
|
||||
private VcnIkeSession mIkeSession;
|
||||
|
||||
/**
|
||||
* The last known child configuration.
|
||||
@@ -774,7 +769,70 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
*/
|
||||
private class DisconnectingState extends ActiveBaseState {
|
||||
@Override
|
||||
protected void processStateMsg(Message msg) {}
|
||||
protected void enterState() throws Exception {
|
||||
if (mIkeSession == null) {
|
||||
Slog.wtf(TAG, "IKE session was already closed when entering Disconnecting state.");
|
||||
sendMessage(EVENT_SESSION_CLOSED, mCurrentToken);
|
||||
return;
|
||||
}
|
||||
|
||||
// If underlying network has already been lost, save some time and just kill the session
|
||||
if (mUnderlying == null) {
|
||||
// Will trigger a EVENT_SESSION_CLOSED as IkeSession shuts down.
|
||||
mIkeSession.kill();
|
||||
return;
|
||||
}
|
||||
|
||||
sendMessageDelayed(
|
||||
EVENT_TEARDOWN_TIMEOUT_EXPIRED,
|
||||
mCurrentToken,
|
||||
TimeUnit.SECONDS.toMillis(TEARDOWN_TIMEOUT_SECONDS));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processStateMsg(Message msg) {
|
||||
switch (msg.what) {
|
||||
case EVENT_UNDERLYING_NETWORK_CHANGED: // Fallthrough
|
||||
mUnderlying = ((EventUnderlyingNetworkChangedInfo) msg.obj).newUnderlying;
|
||||
|
||||
// If we received a new underlying network, continue.
|
||||
if (mUnderlying != null) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Fallthrough; no network exists to send IKE close session requests.
|
||||
case EVENT_TEARDOWN_TIMEOUT_EXPIRED:
|
||||
// Grace period ended. Kill session, triggering EVENT_SESSION_CLOSED
|
||||
mIkeSession.kill();
|
||||
|
||||
break;
|
||||
case EVENT_DISCONNECT_REQUESTED:
|
||||
teardownNetwork();
|
||||
|
||||
String reason = ((EventDisconnectRequestedInfo) msg.obj).reason;
|
||||
if (reason.equals(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)) {
|
||||
// Will trigger EVENT_SESSION_CLOSED immediately.
|
||||
mIkeSession.kill();
|
||||
break;
|
||||
}
|
||||
|
||||
// Otherwise we are already in the process of shutting down.
|
||||
break;
|
||||
case EVENT_SESSION_CLOSED:
|
||||
mIkeSession = null;
|
||||
|
||||
if (mIsRunning && mUnderlying != null) {
|
||||
transitionTo(mRetryTimeoutState);
|
||||
} else {
|
||||
teardownNetwork();
|
||||
transitionTo(mDisconnectedState);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
logUnhandledMessage(msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -946,6 +1004,38 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
mIsRunning = isRunning;
|
||||
}
|
||||
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
VcnIkeSession getIkeSession() {
|
||||
return mIkeSession;
|
||||
}
|
||||
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
void setIkeSession(@Nullable VcnIkeSession session) {
|
||||
mIkeSession = session;
|
||||
}
|
||||
|
||||
private IkeSessionParams buildIkeParams() {
|
||||
// TODO: Implement this with ConnectingState
|
||||
return null;
|
||||
}
|
||||
|
||||
private ChildSessionParams buildChildParams() {
|
||||
// TODO: Implement this with ConnectingState
|
||||
return null;
|
||||
}
|
||||
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
VcnIkeSession buildIkeSession() {
|
||||
final int token = ++mCurrentToken;
|
||||
|
||||
return mDeps.newIkeSession(
|
||||
mVcnContext,
|
||||
buildIkeParams(),
|
||||
buildChildParams(),
|
||||
new IkeSessionCallbackImpl(token),
|
||||
new ChildSessionCallbackImpl(token));
|
||||
}
|
||||
|
||||
/** External dependencies used by VcnGatewayConnection, for injection in tests */
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
public static class Dependencies {
|
||||
@@ -958,19 +1048,67 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
}
|
||||
|
||||
/** Builds a new IkeSession. */
|
||||
public IkeSession newIkeSession(
|
||||
public VcnIkeSession newIkeSession(
|
||||
VcnContext vcnContext,
|
||||
IkeSessionParams ikeSessionParams,
|
||||
ChildSessionParams childSessionParams,
|
||||
IkeSessionCallback ikeSessionCallback,
|
||||
ChildSessionCallback childSessionCallback) {
|
||||
return new IkeSession(
|
||||
vcnContext.getContext(),
|
||||
return new VcnIkeSession(
|
||||
vcnContext,
|
||||
ikeSessionParams,
|
||||
childSessionParams,
|
||||
new HandlerExecutor(new Handler(vcnContext.getLooper())),
|
||||
ikeSessionCallback,
|
||||
childSessionCallback);
|
||||
}
|
||||
}
|
||||
|
||||
/** Proxy implementation of IKE session, used for testing. */
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
public static class VcnIkeSession {
|
||||
private final IkeSession mImpl;
|
||||
|
||||
public VcnIkeSession(
|
||||
VcnContext vcnContext,
|
||||
IkeSessionParams ikeSessionParams,
|
||||
ChildSessionParams childSessionParams,
|
||||
IkeSessionCallback ikeSessionCallback,
|
||||
ChildSessionCallback childSessionCallback) {
|
||||
mImpl =
|
||||
new IkeSession(
|
||||
vcnContext.getContext(),
|
||||
ikeSessionParams,
|
||||
childSessionParams,
|
||||
new HandlerExecutor(new Handler(vcnContext.getLooper())),
|
||||
ikeSessionCallback,
|
||||
childSessionCallback);
|
||||
}
|
||||
|
||||
/** Creates a new IKE Child session. */
|
||||
public void openChildSession(
|
||||
@NonNull ChildSessionParams childSessionParams,
|
||||
@NonNull ChildSessionCallback childSessionCallback) {
|
||||
mImpl.openChildSession(childSessionParams, childSessionCallback);
|
||||
}
|
||||
|
||||
/** Closes an IKE session as identified by the ChildSessionCallback. */
|
||||
public void closeChildSession(@NonNull ChildSessionCallback childSessionCallback) {
|
||||
mImpl.closeChildSession(childSessionCallback);
|
||||
}
|
||||
|
||||
/** Gracefully closes this IKE Session, waiting for remote acknowledgement. */
|
||||
public void close() {
|
||||
mImpl.close();
|
||||
}
|
||||
|
||||
/** Forcibly kills this IKE Session, without waiting for a closure confirmation. */
|
||||
public void kill() {
|
||||
mImpl.kill();
|
||||
}
|
||||
|
||||
/** Sets the underlying network used by the IkeSession. */
|
||||
public void setNetwork(@NonNull Network network) {
|
||||
mImpl.setNetwork(network);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.vcn;
|
||||
|
||||
import static com.android.server.vcn.VcnGatewayConnection.TEARDOWN_TIMEOUT_SECONDS;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/** Tests for VcnGatewayConnection.DisconnectedState */
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class VcnGatewayConnectionDisconnectingStateTest extends VcnGatewayConnectionTestBase {
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
mGatewayConnection.setIkeSession(mGatewayConnection.buildIkeSession());
|
||||
|
||||
mGatewayConnection.transitionTo(mGatewayConnection.mDisconnectingState);
|
||||
mTestLooper.dispatchAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIkeSessionClosed() throws Exception {
|
||||
getIkeSessionCallback().onClosed();
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTimeoutExpired() throws Exception {
|
||||
mTestLooper.moveTimeForward(TimeUnit.SECONDS.toMillis(TEARDOWN_TIMEOUT_SECONDS));
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
verify(mMockIkeSession).kill();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTeardown() throws Exception {
|
||||
mGatewayConnection.teardownAsynchronously();
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
// Should do nothing; already tearing down.
|
||||
assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
|
||||
}
|
||||
}
|
||||
@@ -17,11 +17,13 @@
|
||||
package com.android.server.vcn;
|
||||
|
||||
import static com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord;
|
||||
import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession;
|
||||
import static com.android.server.vcn.VcnTestUtils.setupIpSecManager;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.Context;
|
||||
@@ -30,6 +32,7 @@ import android.net.IpSecTunnelInterfaceResponse;
|
||||
import android.net.LinkProperties;
|
||||
import android.net.Network;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.ipsec.ike.IkeSessionCallback;
|
||||
import android.net.vcn.VcnGatewayConnectionConfig;
|
||||
import android.net.vcn.VcnGatewayConnectionConfigTest;
|
||||
import android.os.ParcelUuid;
|
||||
@@ -38,6 +41,7 @@ import android.os.test.TestLooper;
|
||||
import com.android.server.IpSecService;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -68,6 +72,7 @@ public class VcnGatewayConnectionTestBase {
|
||||
|
||||
@NonNull protected final IpSecService mIpSecSvc;
|
||||
|
||||
protected VcnIkeSession mMockIkeSession;
|
||||
protected VcnGatewayConnection mGatewayConnection;
|
||||
|
||||
public VcnGatewayConnectionTestBase() {
|
||||
@@ -100,6 +105,16 @@ public class VcnGatewayConnectionTestBase {
|
||||
TEST_IPSEC_TUNNEL_IFACE);
|
||||
doReturn(resp).when(mIpSecSvc).createTunnelInterface(any(), any(), any(), any(), any());
|
||||
|
||||
mMockIkeSession = mock(VcnIkeSession.class);
|
||||
doReturn(mMockIkeSession).when(mDeps).newIkeSession(any(), any(), any(), any(), any());
|
||||
|
||||
mGatewayConnection = new VcnGatewayConnection(mVcnContext, TEST_SUB_GRP, mConfig, mDeps);
|
||||
}
|
||||
|
||||
protected IkeSessionCallback getIkeSessionCallback() {
|
||||
ArgumentCaptor<IkeSessionCallback> captor =
|
||||
ArgumentCaptor.forClass(IkeSessionCallback.class);
|
||||
verify(mDeps).newIkeSession(any(), any(), any(), captor.capture(), any());
|
||||
return captor.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user