Merge changes Ib439bde4,I5bc0fe94,I72abf1e2,Id1813bcb am: a3fab46d7b

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1611230

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: Ic3863bd060aa8cbdc5aac3e40d65ee03e82c357c
This commit is contained in:
Benedict Wong
2021-03-03 08:41:30 +00:00
committed by Automerger Merge Worker
10 changed files with 271 additions and 66 deletions

View File

@@ -65,7 +65,7 @@ public class UnderlyingNetworkTracker {
@NonNull private final NetworkCallback mRouteSelectionCallback = new RouteSelectionCallback(); @NonNull private final NetworkCallback mRouteSelectionCallback = new RouteSelectionCallback();
@NonNull private TelephonySubscriptionSnapshot mLastSnapshot; @NonNull private TelephonySubscriptionSnapshot mLastSnapshot;
private boolean mIsRunning = true; private boolean mIsQuitting = false;
@Nullable private UnderlyingNetworkRecord mCurrentRecord; @Nullable private UnderlyingNetworkRecord mCurrentRecord;
@Nullable private UnderlyingNetworkRecord.Builder mRecordInProgress; @Nullable private UnderlyingNetworkRecord.Builder mRecordInProgress;
@@ -151,7 +151,7 @@ public class UnderlyingNetworkTracker {
mVcnContext.ensureRunningOnLooperThread(); mVcnContext.ensureRunningOnLooperThread();
// Don't bother re-filing NetworkRequests if this Tracker has been torn down. // Don't bother re-filing NetworkRequests if this Tracker has been torn down.
if (!mIsRunning) { if (mIsQuitting) {
return; return;
} }
@@ -205,7 +205,7 @@ public class UnderlyingNetworkTracker {
} }
mCellBringupCallbacks.clear(); mCellBringupCallbacks.clear();
mIsRunning = false; mIsQuitting = true;
} }
/** Returns whether the currently selected Network matches the given network. */ /** Returns whether the currently selected Network matches the given network. */

View File

@@ -16,6 +16,8 @@
package com.android.server.vcn; package com.android.server.vcn;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static com.android.server.VcnManagementService.VDBG; import static com.android.server.VcnManagementService.VDBG;
import android.annotation.NonNull; 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; 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. */ /** Triggers an immediate teardown of the entire Vcn, including GatewayConnections. */
private static final int MSG_CMD_TEARDOWN = MSG_CMD_BASE; private static final int MSG_CMD_TEARDOWN = MSG_CMD_BASE;
@@ -208,6 +217,9 @@ public class Vcn extends Handler {
case MSG_EVENT_SUBSCRIPTIONS_CHANGED: case MSG_EVENT_SUBSCRIPTIONS_CHANGED:
handleSubscriptionsChanged((TelephonySubscriptionSnapshot) msg.obj); handleSubscriptionsChanged((TelephonySubscriptionSnapshot) msg.obj);
break; break;
case MSG_EVENT_GATEWAY_CONNECTION_QUIT:
handleGatewayConnectionQuit((VcnGatewayConnectionConfig) msg.obj);
break;
case MSG_CMD_TEARDOWN: case MSG_CMD_TEARDOWN:
handleTeardown(); handleTeardown();
break; break;
@@ -263,7 +275,7 @@ public class Vcn extends Handler {
// If preexisting VcnGatewayConnection(s) satisfy request, return // If preexisting VcnGatewayConnection(s) satisfy request, return
for (VcnGatewayConnectionConfig gatewayConnectionConfig : mVcnGatewayConnections.keySet()) { for (VcnGatewayConnectionConfig gatewayConnectionConfig : mVcnGatewayConnections.keySet()) {
if (requestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) { if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
if (VDBG) { if (VDBG) {
Slog.v( Slog.v(
getLogTag(), getLogTag(),
@@ -278,7 +290,7 @@ public class Vcn extends Handler {
// up // up
for (VcnGatewayConnectionConfig gatewayConnectionConfig : for (VcnGatewayConnectionConfig gatewayConnectionConfig :
mConfig.getGatewayConnectionConfigs()) { mConfig.getGatewayConnectionConfigs()) {
if (requestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) { if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
Slog.v( Slog.v(
getLogTag(), getLogTag(),
"Bringing up new VcnGatewayConnection for request " + request.requestId); "Bringing up new VcnGatewayConnection for request " + request.requestId);
@@ -289,12 +301,21 @@ public class Vcn extends Handler {
mSubscriptionGroup, mSubscriptionGroup,
mLastSnapshot, mLastSnapshot,
gatewayConnectionConfig, gatewayConnectionConfig,
new VcnGatewayStatusCallbackImpl()); new VcnGatewayStatusCallbackImpl(gatewayConnectionConfig));
mVcnGatewayConnections.put(gatewayConnectionConfig, vcnGatewayConnection); 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) { private void handleSubscriptionsChanged(@NonNull TelephonySubscriptionSnapshot snapshot) {
mLastSnapshot = snapshot; mLastSnapshot = snapshot;
@@ -305,9 +326,10 @@ public class Vcn extends Handler {
} }
} }
private boolean requestSatisfiedByGatewayConnectionConfig( private boolean isRequestSatisfiedByGatewayConnectionConfig(
@NonNull NetworkRequest request, @NonNull VcnGatewayConnectionConfig config) { @NonNull NetworkRequest request, @NonNull VcnGatewayConnectionConfig config) {
final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder(); final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder();
builder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
for (int cap : config.getAllExposedCapabilities()) { for (int cap : config.getAllExposedCapabilities()) {
builder.addCapability(cap); builder.addCapability(cap);
} }
@@ -339,9 +361,23 @@ public class Vcn extends Handler {
@VcnErrorCode int errorCode, @VcnErrorCode int errorCode,
@Nullable String exceptionClass, @Nullable String exceptionClass,
@Nullable String exceptionMessage); @Nullable String exceptionMessage);
/** Called by a VcnGatewayConnection to indicate that it has fully torn down. */
void onQuit();
} }
private class VcnGatewayStatusCallbackImpl implements VcnGatewayStatusCallback { 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 @Override
public void onEnteredSafeMode() { public void onEnteredSafeMode() {
sendMessage(obtainMessage(MSG_CMD_ENTER_SAFE_MODE)); sendMessage(obtainMessage(MSG_CMD_ENTER_SAFE_MODE));

View File

@@ -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_INTERNAL_ERROR = "Uncaught exception: ";
private static final String DISCONNECT_REASON_UNDERLYING_NETWORK_LOST = private static final String DISCONNECT_REASON_UNDERLYING_NETWORK_LOST =
"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 String DISCONNECT_REASON_TEARDOWN = "teardown() called on VcnTunnel";
private static final int TOKEN_ALL = Integer.MIN_VALUE; 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. */ /** The reason why the disconnect was requested. */
@NonNull public final String reason; @NonNull public final String reason;
EventDisconnectRequestedInfo(@NonNull String reason) { public final boolean shouldQuit;
EventDisconnectRequestedInfo(@NonNull String reason, boolean shouldQuit) {
this.reason = Objects.requireNonNull(reason); this.reason = Objects.requireNonNull(reason);
this.shouldQuit = shouldQuit;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(reason); return Objects.hash(reason, shouldQuit);
} }
@Override @Override
@@ -395,7 +400,7 @@ public class VcnGatewayConnection extends StateMachine {
} }
final EventDisconnectRequestedInfo rhs = (EventDisconnectRequestedInfo) other; final EventDisconnectRequestedInfo rhs = (EventDisconnectRequestedInfo) other;
return reason.equals(rhs.reason); return reason.equals(rhs.reason) && shouldQuit == rhs.shouldQuit;
} }
} }
@@ -488,8 +493,14 @@ public class VcnGatewayConnection extends StateMachine {
*/ */
@NonNull private final VcnWakeLock mWakeLock; @NonNull private final VcnWakeLock mWakeLock;
/** Running state of this VcnGatewayConnection. */ /**
private boolean mIsRunning = true; * Whether the VcnGatewayConnection is in the process of irreversibly quitting.
*
* <p>This variable is false for the lifecycle of the VcnGatewayConnection, until a command to
* teardown has been received. This may be flipped due to events such as the Network becoming
* unwanted, the owning VCN entering safe mode, or an irrecoverable internal failure.
*/
private boolean mIsQuitting = false;
/** /**
* The token used by the primary/current/active session. * The token used by the primary/current/active session.
@@ -622,10 +633,8 @@ public class VcnGatewayConnection extends StateMachine {
* <p>Once torn down, this VcnTunnel CANNOT be started again. * <p>Once torn down, this VcnTunnel CANNOT be started again.
*/ */
public void teardownAsynchronously() { public void teardownAsynchronously() {
sendMessageAndAcquireWakeLock( sendDisconnectRequestedAndAcquireWakelock(
EVENT_DISCONNECT_REQUESTED, DISCONNECT_REASON_TEARDOWN, true /* shouldQuit */);
TOKEN_ALL,
new EventDisconnectRequestedInfo(DISCONNECT_REASON_TEARDOWN));
// TODO: Notify VcnInstance (via callbacks) of permanent teardown of this tunnel, since this // TODO: Notify VcnInstance (via callbacks) of permanent teardown of this tunnel, since this
// is also called asynchronously when a NetworkAgent becomes unwanted // is also called asynchronously when a NetworkAgent becomes unwanted
@@ -646,6 +655,8 @@ public class VcnGatewayConnection extends StateMachine {
cancelSafeModeAlarm(); cancelSafeModeAlarm();
mUnderlyingNetworkTracker.teardown(); mUnderlyingNetworkTracker.teardown();
mGatewayStatusCallback.onQuit();
} }
/** /**
@@ -693,7 +704,7 @@ public class VcnGatewayConnection extends StateMachine {
private void acquireWakeLock() { private void acquireWakeLock() {
mVcnContext.ensureRunningOnLooperThread(); mVcnContext.ensureRunningOnLooperThread();
if (mIsRunning) { if (!mIsQuitting) {
mWakeLock.acquire(); mWakeLock.acquire();
} }
} }
@@ -892,7 +903,7 @@ public class VcnGatewayConnection extends StateMachine {
TOKEN_ALL, TOKEN_ALL,
0 /* arg2 */, 0 /* arg2 */,
new EventDisconnectRequestedInfo( new EventDisconnectRequestedInfo(
DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)); DISCONNECT_REASON_UNDERLYING_NETWORK_LOST, false /* shouldQuit */));
mDisconnectRequestAlarm = mDisconnectRequestAlarm =
createScheduledAlarm( createScheduledAlarm(
DISCONNECT_REQUEST_ALARM, DISCONNECT_REQUEST_ALARM,
@@ -909,7 +920,8 @@ public class VcnGatewayConnection extends StateMachine {
// Cancel any existing disconnect due to previous loss of underlying network // Cancel any existing disconnect due to previous loss of underlying network
removeEqualMessages( removeEqualMessages(
EVENT_DISCONNECT_REQUESTED, EVENT_DISCONNECT_REQUESTED,
new EventDisconnectRequestedInfo(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)); new EventDisconnectRequestedInfo(
DISCONNECT_REASON_UNDERLYING_NETWORK_LOST, false /* shouldQuit */));
} }
private void setRetryTimeoutAlarm(long delay) { private void setRetryTimeoutAlarm(long delay) {
@@ -1041,11 +1053,8 @@ public class VcnGatewayConnection extends StateMachine {
enterState(); enterState();
} catch (Exception e) { } catch (Exception e) {
Slog.wtf(TAG, "Uncaught exception", e); Slog.wtf(TAG, "Uncaught exception", e);
sendMessageAndAcquireWakeLock( sendDisconnectRequestedAndAcquireWakelock(
EVENT_DISCONNECT_REQUESTED, DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldQuit */);
TOKEN_ALL,
new EventDisconnectRequestedInfo(
DISCONNECT_REASON_INTERNAL_ERROR + e.toString()));
} }
} }
@@ -1083,11 +1092,8 @@ public class VcnGatewayConnection extends StateMachine {
processStateMsg(msg); processStateMsg(msg);
} catch (Exception e) { } catch (Exception e) {
Slog.wtf(TAG, "Uncaught exception", e); Slog.wtf(TAG, "Uncaught exception", e);
sendMessageAndAcquireWakeLock( sendDisconnectRequestedAndAcquireWakelock(
EVENT_DISCONNECT_REQUESTED, DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldQuit */);
TOKEN_ALL,
new EventDisconnectRequestedInfo(
DISCONNECT_REASON_INTERNAL_ERROR + e.toString()));
} }
// Attempt to release the WakeLock - only possible if the Handler queue is empty // Attempt to release the WakeLock - only possible if the Handler queue is empty
@@ -1104,11 +1110,8 @@ public class VcnGatewayConnection extends StateMachine {
exitState(); exitState();
} catch (Exception e) { } catch (Exception e) {
Slog.wtf(TAG, "Uncaught exception", e); Slog.wtf(TAG, "Uncaught exception", e);
sendMessageAndAcquireWakeLock( sendDisconnectRequestedAndAcquireWakelock(
EVENT_DISCONNECT_REQUESTED, DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldQuit */);
TOKEN_ALL,
new EventDisconnectRequestedInfo(
DISCONNECT_REASON_INTERNAL_ERROR + e.toString()));
} }
} }
@@ -1141,11 +1144,11 @@ public class VcnGatewayConnection extends StateMachine {
} }
} }
protected void handleDisconnectRequested(String msg) { protected void handleDisconnectRequested(EventDisconnectRequestedInfo info) {
// TODO(b/180526152): notify VcnStatusCallback for Network loss // TODO(b/180526152): notify VcnStatusCallback for Network loss
Slog.v(TAG, "Tearing down. Cause: " + msg); Slog.v(TAG, "Tearing down. Cause: " + info.reason);
mIsRunning = false; mIsQuitting = info.shouldQuit;
teardownNetwork(); teardownNetwork();
@@ -1177,7 +1180,7 @@ public class VcnGatewayConnection extends StateMachine {
private class DisconnectedState extends BaseState { private class DisconnectedState extends BaseState {
@Override @Override
protected void enterState() { protected void enterState() {
if (!mIsRunning) { if (mIsQuitting) {
quitNow(); // Ignore all queued events; cleanup is complete. quitNow(); // Ignore all queued events; cleanup is complete.
} }
@@ -1200,9 +1203,11 @@ public class VcnGatewayConnection extends StateMachine {
} }
break; break;
case EVENT_DISCONNECT_REQUESTED: case EVENT_DISCONNECT_REQUESTED:
mIsRunning = false; if (((EventDisconnectRequestedInfo) msg.obj).shouldQuit) {
mIsQuitting = true;
quitNow(); quitNow();
}
break; break;
default: default:
logUnhandledMessage(msg); logUnhandledMessage(msg);
@@ -1284,10 +1289,11 @@ public class VcnGatewayConnection extends StateMachine {
break; break;
case EVENT_DISCONNECT_REQUESTED: case EVENT_DISCONNECT_REQUESTED:
EventDisconnectRequestedInfo info = ((EventDisconnectRequestedInfo) msg.obj);
mIsQuitting = info.shouldQuit;
teardownNetwork(); teardownNetwork();
String reason = ((EventDisconnectRequestedInfo) msg.obj).reason; if (info.reason.equals(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)) {
if (reason.equals(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)) {
// TODO(b/180526152): notify VcnStatusCallback for Network loss // TODO(b/180526152): notify VcnStatusCallback for Network loss
// Will trigger EVENT_SESSION_CLOSED immediately. // Will trigger EVENT_SESSION_CLOSED immediately.
@@ -1300,7 +1306,7 @@ public class VcnGatewayConnection extends StateMachine {
case EVENT_SESSION_CLOSED: case EVENT_SESSION_CLOSED:
mIkeSession = null; mIkeSession = null;
if (mIsRunning && mUnderlying != null) { if (!mIsQuitting && mUnderlying != null) {
transitionTo(mSkipRetryTimeout ? mConnectingState : mRetryTimeoutState); transitionTo(mSkipRetryTimeout ? mConnectingState : mRetryTimeoutState);
} else { } else {
teardownNetwork(); teardownNetwork();
@@ -1391,7 +1397,7 @@ public class VcnGatewayConnection extends StateMachine {
transitionTo(mConnectedState); transitionTo(mConnectedState);
break; break;
case EVENT_DISCONNECT_REQUESTED: case EVENT_DISCONNECT_REQUESTED:
handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason); handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj);
break; break;
case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED: case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
mGatewayStatusCallback.onEnteredSafeMode(); mGatewayStatusCallback.onEnteredSafeMode();
@@ -1438,6 +1444,7 @@ public class VcnGatewayConnection extends StateMachine {
mVcnContext.getVcnNetworkProvider()) { mVcnContext.getVcnNetworkProvider()) {
@Override @Override
public void unwanted() { public void unwanted() {
Slog.d(TAG, "NetworkAgent was unwanted");
teardownAsynchronously(); teardownAsynchronously();
} }
@@ -1471,7 +1478,7 @@ public class VcnGatewayConnection extends StateMachine {
@NonNull IpSecTransform transform, @NonNull IpSecTransform transform,
int direction) { int direction) {
try { try {
// TODO(b/180163196): Set underlying network of tunnel interface tunnelIface.setUnderlyingNetwork(underlyingNetwork);
// Transforms do not need to be persisted; the IkeSession will keep them alive // Transforms do not need to be persisted; the IkeSession will keep them alive
mIpSecManager.applyTunnelModeTransform(tunnelIface, direction, transform); mIpSecManager.applyTunnelModeTransform(tunnelIface, direction, transform);
@@ -1577,7 +1584,7 @@ public class VcnGatewayConnection extends StateMachine {
setupInterfaceAndNetworkAgent(mCurrentToken, mTunnelIface, mChildConfig); setupInterfaceAndNetworkAgent(mCurrentToken, mTunnelIface, mChildConfig);
break; break;
case EVENT_DISCONNECT_REQUESTED: case EVENT_DISCONNECT_REQUESTED:
handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason); handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj);
break; break;
case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED: case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
mGatewayStatusCallback.onEnteredSafeMode(); mGatewayStatusCallback.onEnteredSafeMode();
@@ -1682,7 +1689,7 @@ public class VcnGatewayConnection extends StateMachine {
transitionTo(mConnectingState); transitionTo(mConnectingState);
break; break;
case EVENT_DISCONNECT_REQUESTED: case EVENT_DISCONNECT_REQUESTED:
handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason); handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj);
break; break;
case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED: case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
mGatewayStatusCallback.onEnteredSafeMode(); mGatewayStatusCallback.onEnteredSafeMode();
@@ -1905,13 +1912,13 @@ public class VcnGatewayConnection extends StateMachine {
} }
@VisibleForTesting(visibility = Visibility.PRIVATE) @VisibleForTesting(visibility = Visibility.PRIVATE)
boolean isRunning() { boolean isQuitting() {
return mIsRunning; return mIsQuitting;
} }
@VisibleForTesting(visibility = Visibility.PRIVATE) @VisibleForTesting(visibility = Visibility.PRIVATE)
void setIsRunning(boolean isRunning) { void setIsQuitting(boolean isQuitting) {
mIsRunning = isRunning; mIsQuitting = isQuitting;
} }
@VisibleForTesting(visibility = Visibility.PRIVATE) @VisibleForTesting(visibility = Visibility.PRIVATE)
@@ -1924,6 +1931,14 @@ public class VcnGatewayConnection extends StateMachine {
mIkeSession = session; mIkeSession = session;
} }
@VisibleForTesting(visibility = Visibility.PRIVATE)
void sendDisconnectRequestedAndAcquireWakelock(String reason, boolean shouldQuit) {
sendMessageAndAcquireWakeLock(
EVENT_DISCONNECT_REQUESTED,
TOKEN_ALL,
new EventDisconnectRequestedInfo(reason, shouldQuit));
}
private IkeSessionParams buildIkeParams() { private IkeSessionParams buildIkeParams() {
// TODO: Implement this once IkeSessionParams is persisted // TODO: Implement this once IkeSessionParams is persisted
return null; return null;

View File

@@ -67,9 +67,7 @@ public class VcnNetworkProvider extends NetworkProvider {
mListeners.add(listener); mListeners.add(listener);
// Send listener all cached requests // Send listener all cached requests
for (NetworkRequestEntry entry : mRequests.values()) { resendAllRequests(listener);
notifyListenerForEvent(listener, entry);
}
} }
/** Unregisters the specified listener from receiving future NetworkRequests. */ /** Unregisters the specified listener from receiving future NetworkRequests. */
@@ -78,6 +76,14 @@ public class VcnNetworkProvider extends NetworkProvider {
mListeners.remove(listener); 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( private void notifyListenerForEvent(
@NonNull NetworkRequestListener listener, @NonNull NetworkRequestEntry entry) { @NonNull NetworkRequestListener listener, @NonNull NetworkRequestEntry entry) {
listener.onNetworkRequested(entry.mRequest, entry.mScore, entry.mProviderId); listener.onNetworkRequested(entry.mRequest, entry.mScore, entry.mProviderId);

View File

@@ -36,6 +36,7 @@ import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -143,11 +144,18 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
.onIpSecTransformsMigrated(makeDummyIpSecTransform(), makeDummyIpSecTransform()); .onIpSecTransformsMigrated(makeDummyIpSecTransform(), makeDummyIpSecTransform());
mTestLooper.dispatchAll(); mTestLooper.dispatchAll();
verify(mIpSecSvc, times(2))
.setNetworkForTunnelInterface(
eq(TEST_IPSEC_TUNNEL_RESOURCE_ID),
eq(TEST_UNDERLYING_NETWORK_RECORD_1.network),
any());
for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT}) { for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT}) {
verify(mIpSecSvc) verify(mIpSecSvc)
.applyTunnelModeTransform( .applyTunnelModeTransform(
eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(direction), anyInt(), any()); eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(direction), anyInt(), any());
} }
assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
} }
@@ -290,4 +298,22 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
verifyIkeSessionClosedExceptionalltyNotifiesStatusCallback( verifyIkeSessionClosedExceptionalltyNotifiesStatusCallback(
new TemporaryFailureException("vcn test"), VCN_ERROR_CODE_INTERNAL_ERROR); new TemporaryFailureException("vcn test"), VCN_ERROR_CODE_INTERNAL_ERROR);
} }
@Test
public void testTeardown() throws Exception {
mGatewayConnection.teardownAsynchronously();
mTestLooper.dispatchAll();
assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
assertTrue(mGatewayConnection.isQuitting());
}
@Test
public void testNonTeardownDisconnectRequest() throws Exception {
mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false);
mTestLooper.dispatchAll();
assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
assertFalse(mGatewayConnection.isQuitting());
}
} }

View File

@@ -19,6 +19,8 @@ package com.android.server.vcn;
import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession;
import static org.junit.Assert.assertEquals; 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.Matchers.any;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
@@ -111,4 +113,22 @@ public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectio
public void testSafeModeTimeoutNotifiesCallback() { public void testSafeModeTimeoutNotifiesCallback() {
verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mConnectingState); verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mConnectingState);
} }
@Test
public void testTeardown() throws Exception {
mGatewayConnection.teardownAsynchronously();
mTestLooper.dispatchAll();
assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
assertTrue(mGatewayConnection.isQuitting());
}
@Test
public void testNonTeardownDisconnectRequest() throws Exception {
mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false);
mTestLooper.dispatchAll();
assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
assertFalse(mGatewayConnection.isQuitting());
}
} }

View File

@@ -21,9 +21,12 @@ import static android.net.IpSecManager.IpSecTunnelInterface;
import static com.android.server.vcn.VcnGatewayConnection.DUMMY_ADDR; import static com.android.server.vcn.VcnGatewayConnection.DUMMY_ADDR;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import android.net.IpSecManager; import android.net.IpSecManager;
@@ -54,7 +57,7 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect
} }
@Test @Test
public void testEnterWhileNotRunningTriggersQuit() throws Exception { public void testEnterWhileQuittingTriggersQuit() throws Exception {
final VcnGatewayConnection vgc = final VcnGatewayConnection vgc =
new VcnGatewayConnection( new VcnGatewayConnection(
mVcnContext, mVcnContext,
@@ -64,7 +67,7 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect
mGatewayStatusCallback, mGatewayStatusCallback,
mDeps); mDeps);
vgc.setIsRunning(false); vgc.setIsQuitting(true);
vgc.transitionTo(vgc.mDisconnectedState); vgc.transitionTo(vgc.mDisconnectedState);
mTestLooper.dispatchAll(); mTestLooper.dispatchAll();
@@ -101,5 +104,18 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect
assertNull(mGatewayConnection.getCurrentState()); assertNull(mGatewayConnection.getCurrentState());
verify(mIpSecSvc).deleteTunnelInterface(eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), any()); verify(mIpSecSvc).deleteTunnelInterface(eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), any());
verifySafeModeTimeoutAlarmAndGetCallback(true /* expectCanceled */); verifySafeModeTimeoutAlarmAndGetCallback(true /* expectCanceled */);
assertTrue(mGatewayConnection.isQuitting());
verify(mGatewayStatusCallback).onQuit();
}
@Test
public void testNonTeardownDisconnectRequest() throws Exception {
mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false);
mTestLooper.dispatchAll();
assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState());
assertFalse(mGatewayConnection.isQuitting());
verify(mGatewayStatusCallback, never()).onQuit();
// No safe mode timer changes expected.
} }
} }

View File

@@ -18,6 +18,8 @@ package com.android.server.vcn;
import static org.junit.Assert.assertEquals; 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.never;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
@@ -79,10 +81,20 @@ public class VcnGatewayConnectionDisconnectingStateTest extends VcnGatewayConnec
// Should do nothing; already tearing down. // Should do nothing; already tearing down.
assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */); verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */);
assertTrue(mGatewayConnection.isQuitting());
} }
@Test @Test
public void testSafeModeTimeoutNotifiesCallback() { public void testSafeModeTimeoutNotifiesCallback() {
verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mDisconnectingState); verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mDisconnectingState);
} }
@Test
public void testNonTeardownDisconnectRequest() throws Exception {
mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false);
mTestLooper.dispatchAll();
assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
assertFalse(mGatewayConnection.isQuitting());
}
} }

View File

@@ -17,6 +17,9 @@
package com.android.server.vcn; package com.android.server.vcn;
import static org.junit.Assert.assertEquals; 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.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4; import androidx.test.runner.AndroidJUnit4;
@@ -96,4 +99,22 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect
public void testSafeModeTimeoutNotifiesCallback() { public void testSafeModeTimeoutNotifiesCallback() {
verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mRetryTimeoutState); verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mRetryTimeoutState);
} }
@Test
public void testTeardownDisconnectRequest() throws Exception {
mGatewayConnection.teardownAsynchronously();
mTestLooper.dispatchAll();
assertNull(mGatewayConnection.getCurrentState());
assertTrue(mGatewayConnection.isQuitting());
}
@Test
public void testNonTeardownDisconnectRequest() throws Exception {
mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false);
mTestLooper.dispatchAll();
assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState());
assertFalse(mGatewayConnection.isQuitting());
}
} }

View File

@@ -16,6 +16,10 @@
package com.android.server.vcn; 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.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
@@ -33,6 +37,7 @@ import android.net.vcn.VcnGatewayConnectionConfig;
import android.net.vcn.VcnGatewayConnectionConfigTest; import android.net.vcn.VcnGatewayConnectionConfigTest;
import android.os.ParcelUuid; import android.os.ParcelUuid;
import android.os.test.TestLooper; import android.os.test.TestLooper;
import android.util.ArraySet;
import com.android.server.VcnManagementService.VcnCallback; import com.android.server.VcnManagementService.VcnCallback;
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; 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 ParcelUuid TEST_SUB_GROUP = new ParcelUuid(new UUID(0, 0));
private static final int NETWORK_SCORE = 0; private static final int NETWORK_SCORE = 0;
private static final int PROVIDER_ID = 5; 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 Context mContext;
private VcnContext mVcnContext; private VcnContext mVcnContext;
@@ -91,13 +101,12 @@ public class VcnTest {
mGatewayStatusCallbackCaptor = ArgumentCaptor.forClass(VcnGatewayStatusCallback.class); mGatewayStatusCallbackCaptor = ArgumentCaptor.forClass(VcnGatewayStatusCallback.class);
final VcnConfig.Builder configBuilder = new VcnConfig.Builder(mContext); final VcnConfig.Builder configBuilder = new VcnConfig.Builder(mContext);
for (final int capability : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) { for (final int[] caps : TEST_CAPS) {
configBuilder.addGatewayConnectionConfig( configBuilder.addGatewayConnectionConfig(
VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(capability)); VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(caps));
} }
configBuilder.addGatewayConnectionConfig(VcnGatewayConnectionConfigTest.buildTestConfig());
mConfig = configBuilder.build();
mConfig = configBuilder.build();
mVcn = mVcn =
new Vcn( new Vcn(
mVcnContext, mVcnContext,
@@ -130,8 +139,7 @@ public class VcnTest {
@Test @Test
public void testSubscriptionSnapshotUpdatesVcnGatewayConnections() { public void testSubscriptionSnapshotUpdatesVcnGatewayConnections() {
final NetworkRequestListener requestListener = verifyAndGetRequestListener(); final NetworkRequestListener requestListener = verifyAndGetRequestListener();
startVcnGatewayWithCapabilities( startVcnGatewayWithCapabilities(requestListener, TEST_CAPS[0]);
requestListener, VcnGatewayConnectionConfigTest.EXPOSED_CAPS);
final Set<VcnGatewayConnection> gatewayConnections = mVcn.getVcnGatewayConnections(); final Set<VcnGatewayConnection> gatewayConnections = mVcn.getVcnGatewayConnections();
assertFalse(gatewayConnections.isEmpty()); assertFalse(gatewayConnections.isEmpty());
@@ -153,10 +161,19 @@ public class VcnTest {
for (final int capability : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) { for (final int capability : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) {
startVcnGatewayWithCapabilities(requestListener, capability); startVcnGatewayWithCapabilities(requestListener, capability);
} }
}
// Each Capability in EXPOSED_CAPS was split into a separate VcnGatewayConnection in #setUp. private void triggerVcnRequestListeners(NetworkRequestListener requestListener) {
// Expect one VcnGatewayConnection per capability. for (final int[] caps : TEST_CAPS) {
final int numExpectedGateways = VcnGatewayConnectionConfigTest.EXPOSED_CAPS.length; startVcnGatewayWithCapabilities(requestListener, caps);
}
}
public Set<VcnGatewayConnection> startGatewaysAndGetGatewayConnections(
NetworkRequestListener requestListener) {
triggerVcnRequestListeners(requestListener);
final int numExpectedGateways = TEST_CAPS.length;
final Set<VcnGatewayConnection> gatewayConnections = mVcn.getVcnGatewayConnections(); final Set<VcnGatewayConnection> gatewayConnections = mVcn.getVcnGatewayConnections();
assertEquals(numExpectedGateways, gatewayConnections.size()); assertEquals(numExpectedGateways, gatewayConnections.size());
@@ -168,7 +185,16 @@ public class VcnTest {
any(), any(),
mGatewayStatusCallbackCaptor.capture()); 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 // all Gateways
final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue(); final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue();
statusCallback.onEnteredSafeMode(); statusCallback.onEnteredSafeMode();
@@ -181,4 +207,31 @@ public class VcnTest {
verify(mVcnNetworkProvider).unregisterListener(requestListener); verify(mVcnNetworkProvider).unregisterListener(requestListener);
verify(mVcnCallback).onEnteredSafeMode(); 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());
}
} }