Merge changes Icf32cb46,I43434c80,I59dc46dc,I7df3f14b,I50f2c0e9
* changes: Don't process dup unwanted() when unregistering NetworkAgent Add/remove internal addresses from IpSecTunnelInterface Populate legacy type in VCN NetworkAgentConfig Add TRANSPORT_CELLULAR to VCN filter Allow soft-start and opportunistic safe mode
This commit is contained in:
@@ -542,16 +542,7 @@ public class VcnManagementService extends IVcnManagementService.Stub {
|
||||
|
||||
if (mVcns.containsKey(subscriptionGroup)) {
|
||||
final Vcn vcn = mVcns.get(subscriptionGroup);
|
||||
final int status = vcn.getStatus();
|
||||
vcn.updateConfig(config);
|
||||
|
||||
// TODO(b/183174340): Remove this once opportunistic-safe-mode is supported
|
||||
// Only notify VcnStatusCallbacks if this VCN was previously in Safe Mode
|
||||
if (status == VCN_STATUS_CODE_SAFE_MODE) {
|
||||
// TODO(b/181789060): invoke asynchronously after Vcn notifies through VcnCallback
|
||||
notifyAllPermissionedStatusCallbacksLocked(
|
||||
subscriptionGroup, VCN_STATUS_CODE_ACTIVE);
|
||||
}
|
||||
} else {
|
||||
startVcnLocked(subscriptionGroup, config);
|
||||
}
|
||||
@@ -941,8 +932,8 @@ public class VcnManagementService extends IVcnManagementService.Stub {
|
||||
// TODO(b/180452282): Make name more generic and implement directly with VcnManagementService
|
||||
/** Callback for Vcn signals sent up to VcnManagementService. */
|
||||
public interface VcnCallback {
|
||||
/** Called by a Vcn to signal that it has entered safe mode. */
|
||||
void onEnteredSafeMode();
|
||||
/** Called by a Vcn to signal that its safe mode status has changed. */
|
||||
void onSafeModeStatusChanged(boolean isInSafeMode);
|
||||
|
||||
/** Called by a Vcn to signal that an error occurred. */
|
||||
void onGatewayConnectionError(
|
||||
@@ -1004,15 +995,18 @@ public class VcnManagementService extends IVcnManagementService.Stub {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnteredSafeMode() {
|
||||
public void onSafeModeStatusChanged(boolean isInSafeMode) {
|
||||
synchronized (mLock) {
|
||||
// Ignore if this subscription group doesn't exist anymore
|
||||
if (!mVcns.containsKey(mSubGroup)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int status =
|
||||
isInSafeMode ? VCN_STATUS_CODE_SAFE_MODE : VCN_STATUS_CODE_ACTIVE;
|
||||
|
||||
notifyAllPolicyListenersLocked();
|
||||
notifyAllPermissionedStatusCallbacksLocked(mSubGroup, VCN_STATUS_CODE_SAFE_MODE);
|
||||
notifyAllPermissionedStatusCallbacksLocked(mSubGroup, status);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.android.server.vcn;
|
||||
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
|
||||
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
|
||||
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
|
||||
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE;
|
||||
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
|
||||
@@ -96,17 +97,21 @@ public class Vcn extends Handler {
|
||||
*/
|
||||
private static final int MSG_EVENT_GATEWAY_CONNECTION_QUIT = MSG_EVENT_BASE + 3;
|
||||
|
||||
/**
|
||||
* Triggers reevaluation of safe mode conditions.
|
||||
*
|
||||
* <p>Upon entering safe mode, the VCN will only provide gateway connections opportunistically,
|
||||
* leaving the underlying networks marked as NOT_VCN_MANAGED.
|
||||
*
|
||||
* <p>Any VcnGatewayConnection in safe mode will result in the entire Vcn instance being put
|
||||
* into safe mode. Upon receiving this message, the Vcn MUST query all VcnGatewayConnections to
|
||||
* determine if any are in safe mode.
|
||||
*/
|
||||
private static final int MSG_EVENT_SAFE_MODE_STATE_CHANGED = MSG_EVENT_BASE + 4;
|
||||
|
||||
/** Triggers an immediate teardown of the entire Vcn, including GatewayConnections. */
|
||||
private static final int MSG_CMD_TEARDOWN = MSG_CMD_BASE;
|
||||
|
||||
/**
|
||||
* Causes this VCN to immediately enter safe mode.
|
||||
*
|
||||
* <p>Upon entering safe mode, the VCN will unregister its RequestListener, tear down all of its
|
||||
* VcnGatewayConnections, and notify VcnManagementService that it is in safe mode.
|
||||
*/
|
||||
private static final int MSG_CMD_ENTER_SAFE_MODE = MSG_CMD_BASE + 1;
|
||||
|
||||
@NonNull private final VcnContext mVcnContext;
|
||||
@NonNull private final ParcelUuid mSubscriptionGroup;
|
||||
@NonNull private final Dependencies mDeps;
|
||||
@@ -233,6 +238,11 @@ public class Vcn extends Handler {
|
||||
|
||||
@Override
|
||||
public void handleMessage(@NonNull Message msg) {
|
||||
if (mCurrentStatus != VCN_STATUS_CODE_ACTIVE
|
||||
&& mCurrentStatus != VCN_STATUS_CODE_SAFE_MODE) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (msg.what) {
|
||||
case MSG_EVENT_CONFIG_UPDATED:
|
||||
handleConfigUpdated((VcnConfig) msg.obj);
|
||||
@@ -246,12 +256,12 @@ public class Vcn extends Handler {
|
||||
case MSG_EVENT_GATEWAY_CONNECTION_QUIT:
|
||||
handleGatewayConnectionQuit((VcnGatewayConnectionConfig) msg.obj);
|
||||
break;
|
||||
case MSG_EVENT_SAFE_MODE_STATE_CHANGED:
|
||||
handleSafeModeStatusChanged();
|
||||
break;
|
||||
case MSG_CMD_TEARDOWN:
|
||||
handleTeardown();
|
||||
break;
|
||||
case MSG_CMD_ENTER_SAFE_MODE:
|
||||
handleEnterSafeMode();
|
||||
break;
|
||||
default:
|
||||
Slog.wtf(getLogTag(), "Unknown msg.what: " + msg.what);
|
||||
}
|
||||
@@ -263,40 +273,28 @@ public class Vcn extends Handler {
|
||||
|
||||
mConfig = config;
|
||||
|
||||
// TODO(b/183174340): Remove this once opportunistic safe mode is supported.
|
||||
if (mCurrentStatus == VCN_STATUS_CODE_ACTIVE) {
|
||||
// VCN is already active - teardown any GatewayConnections whose configs have been
|
||||
// removed and get all current requests
|
||||
for (final Entry<VcnGatewayConnectionConfig, VcnGatewayConnection> entry :
|
||||
mVcnGatewayConnections.entrySet()) {
|
||||
final VcnGatewayConnectionConfig gatewayConnectionConfig = entry.getKey();
|
||||
final VcnGatewayConnection gatewayConnection = entry.getValue();
|
||||
// Teardown any GatewayConnections whose configs have been removed and get all current
|
||||
// requests
|
||||
for (final Entry<VcnGatewayConnectionConfig, VcnGatewayConnection> entry :
|
||||
mVcnGatewayConnections.entrySet()) {
|
||||
final VcnGatewayConnectionConfig gatewayConnectionConfig = entry.getKey();
|
||||
final VcnGatewayConnection gatewayConnection = entry.getValue();
|
||||
|
||||
// GatewayConnectionConfigs must match exactly (otherwise authentication or
|
||||
// connection details may have changed).
|
||||
if (!mConfig.getGatewayConnectionConfigs().contains(gatewayConnectionConfig)) {
|
||||
if (gatewayConnection == null) {
|
||||
Slog.wtf(
|
||||
getLogTag(),
|
||||
"Found gatewayConnectionConfig without GatewayConnection");
|
||||
} else {
|
||||
gatewayConnection.teardownAsynchronously();
|
||||
}
|
||||
// GatewayConnectionConfigs must match exactly (otherwise authentication or
|
||||
// connection details may have changed).
|
||||
if (!mConfig.getGatewayConnectionConfigs().contains(gatewayConnectionConfig)) {
|
||||
if (gatewayConnection == null) {
|
||||
Slog.wtf(
|
||||
getLogTag(), "Found gatewayConnectionConfig without GatewayConnection");
|
||||
} else {
|
||||
gatewayConnection.teardownAsynchronously();
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger a re-evaluation of all NetworkRequests (to make sure any that can be
|
||||
// satisfied start a new GatewayConnection)
|
||||
mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener);
|
||||
} else if (mCurrentStatus == VCN_STATUS_CODE_SAFE_MODE) {
|
||||
// If this VCN was not previously active, it is exiting Safe Mode. Re-register the
|
||||
// request listener to get NetworkRequests again (and all cached requests).
|
||||
mVcnContext.getVcnNetworkProvider().registerListener(mRequestListener);
|
||||
} else {
|
||||
// Ignored; VCN was not active; config updates ignored.
|
||||
return;
|
||||
}
|
||||
mCurrentStatus = VCN_STATUS_CODE_ACTIVE;
|
||||
|
||||
// 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 handleTeardown() {
|
||||
@@ -309,21 +307,27 @@ public class Vcn extends Handler {
|
||||
mCurrentStatus = VCN_STATUS_CODE_INACTIVE;
|
||||
}
|
||||
|
||||
private void handleEnterSafeMode() {
|
||||
// TODO(b/183174340): Remove this once opportunistic-safe-mode is supported
|
||||
handleTeardown();
|
||||
private void handleSafeModeStatusChanged() {
|
||||
boolean hasSafeModeGatewayConnection = false;
|
||||
|
||||
mCurrentStatus = VCN_STATUS_CODE_SAFE_MODE;
|
||||
mVcnCallback.onEnteredSafeMode();
|
||||
// If any VcnGatewayConnection is in safe mode, mark the entire VCN as being in safe mode
|
||||
for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) {
|
||||
if (gatewayConnection.isInSafeMode()) {
|
||||
hasSafeModeGatewayConnection = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
final int oldStatus = mCurrentStatus;
|
||||
mCurrentStatus =
|
||||
hasSafeModeGatewayConnection ? VCN_STATUS_CODE_SAFE_MODE : VCN_STATUS_CODE_ACTIVE;
|
||||
if (oldStatus != mCurrentStatus) {
|
||||
mVcnCallback.onSafeModeStatusChanged(hasSafeModeGatewayConnection);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleNetworkRequested(
|
||||
@NonNull NetworkRequest request, int score, int providerId) {
|
||||
if (mCurrentStatus != VCN_STATUS_CODE_ACTIVE) {
|
||||
Slog.v(getLogTag(), "Received NetworkRequest while inactive. Ignore for now");
|
||||
return;
|
||||
}
|
||||
|
||||
if (score > getNetworkScore()) {
|
||||
if (VDBG) {
|
||||
Slog.v(
|
||||
@@ -376,25 +380,23 @@ public class Vcn extends Handler {
|
||||
mVcnGatewayConnections.remove(config);
|
||||
|
||||
// Trigger a re-evaluation of all NetworkRequests (to make sure any that can be satisfied
|
||||
// start a new GatewayConnection), but only if the Vcn is still alive
|
||||
if (mCurrentStatus == VCN_STATUS_CODE_ACTIVE) {
|
||||
mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener);
|
||||
}
|
||||
// start a new GatewayConnection). VCN is always alive here, courtesy of the liveness check
|
||||
// in handleMessage()
|
||||
mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener);
|
||||
}
|
||||
|
||||
private void handleSubscriptionsChanged(@NonNull TelephonySubscriptionSnapshot snapshot) {
|
||||
mLastSnapshot = snapshot;
|
||||
|
||||
if (mCurrentStatus == VCN_STATUS_CODE_ACTIVE) {
|
||||
for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) {
|
||||
gatewayConnection.updateSubscriptionSnapshot(mLastSnapshot);
|
||||
}
|
||||
for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) {
|
||||
gatewayConnection.updateSubscriptionSnapshot(mLastSnapshot);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isRequestSatisfiedByGatewayConnectionConfig(
|
||||
@NonNull NetworkRequest request, @NonNull VcnGatewayConnectionConfig config) {
|
||||
final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder();
|
||||
builder.addTransportType(TRANSPORT_CELLULAR);
|
||||
builder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
|
||||
for (int cap : config.getAllExposedCapabilities()) {
|
||||
builder.addCapability(cap);
|
||||
@@ -418,8 +420,8 @@ public class Vcn extends Handler {
|
||||
/** Callback used for passing status signals from a VcnGatewayConnection to its managing Vcn. */
|
||||
@VisibleForTesting(visibility = Visibility.PACKAGE)
|
||||
public interface VcnGatewayStatusCallback {
|
||||
/** Called by a VcnGatewayConnection to indicate that it has entered safe mode. */
|
||||
void onEnteredSafeMode();
|
||||
/** Called by a VcnGatewayConnection to indicate that it's safe mode status has changed. */
|
||||
void onSafeModeStatusChanged();
|
||||
|
||||
/** Callback by a VcnGatewayConnection to indicate that an error occurred. */
|
||||
void onGatewayConnectionError(
|
||||
@@ -445,8 +447,8 @@ public class Vcn extends Handler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnteredSafeMode() {
|
||||
sendMessage(obtainMessage(MSG_CMD_ENTER_SAFE_MODE));
|
||||
public void onSafeModeStatusChanged() {
|
||||
sendMessage(obtainMessage(MSG_EVENT_SAFE_MODE_STATE_CHANGED));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -32,6 +32,7 @@ import static com.android.server.VcnManagementService.VDBG;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.InetAddresses;
|
||||
import android.net.IpPrefix;
|
||||
import android.net.IpSecManager;
|
||||
@@ -44,6 +45,7 @@ import android.net.Network;
|
||||
import android.net.NetworkAgent;
|
||||
import android.net.NetworkAgentConfig;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.NetworkProvider;
|
||||
import android.net.RouteInfo;
|
||||
import android.net.TelephonyNetworkSpecifier;
|
||||
import android.net.Uri;
|
||||
@@ -92,6 +94,7 @@ import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* A single VCN Gateway Connection, providing a single public-facing VCN network.
|
||||
@@ -503,6 +506,15 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
*/
|
||||
private boolean mIsQuitting = false;
|
||||
|
||||
/**
|
||||
* Whether the VcnGatewayConnection is in safe mode.
|
||||
*
|
||||
* <p>Upon hitting the safe mode timeout, this will be set to {@code true}. In safe mode, this
|
||||
* VcnGatewayConnection will continue attempting to connect, and if a successful connection is
|
||||
* made, safe mode will be exited.
|
||||
*/
|
||||
private boolean mIsInSafeMode = false;
|
||||
|
||||
/**
|
||||
* The token used by the primary/current/active session.
|
||||
*
|
||||
@@ -562,8 +574,7 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
* <p>Set in Connected state, always @NonNull in Connected, Migrating states, @Nullable
|
||||
* otherwise.
|
||||
*/
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
NetworkAgent mNetworkAgent;
|
||||
private NetworkAgent mNetworkAgent;
|
||||
|
||||
@Nullable private WakeupMessage mTeardownTimeoutAlarm;
|
||||
@Nullable private WakeupMessage mDisconnectRequestAlarm;
|
||||
@@ -628,6 +639,14 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
start();
|
||||
}
|
||||
|
||||
/** Queries whether this VcnGatewayConnection is in safe mode. */
|
||||
public boolean isInSafeMode() {
|
||||
// Accessing internal state; must only be done on looper thread.
|
||||
mVcnContext.ensureRunningOnLooperThread();
|
||||
|
||||
return mIsInSafeMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously tears down this GatewayConnection, and any resources used.
|
||||
*
|
||||
@@ -1162,6 +1181,15 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
}
|
||||
}
|
||||
|
||||
protected void handleSafeModeTimeoutExceeded() {
|
||||
mSafeModeTimeoutAlarm = null;
|
||||
|
||||
// Connectivity for this GatewayConnection is broken; tear down the Network.
|
||||
teardownNetwork();
|
||||
mIsInSafeMode = true;
|
||||
mGatewayStatusCallback.onSafeModeStatusChanged();
|
||||
}
|
||||
|
||||
protected void logUnexpectedEvent(int what) {
|
||||
Slog.d(TAG, String.format(
|
||||
"Unexpected event code %d in state %s", what, this.getClass().getSimpleName()));
|
||||
@@ -1315,8 +1343,7 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
}
|
||||
break;
|
||||
case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
|
||||
mGatewayStatusCallback.onEnteredSafeMode();
|
||||
mSafeModeTimeoutAlarm = null;
|
||||
handleSafeModeTimeoutExceeded();
|
||||
break;
|
||||
default:
|
||||
logUnhandledMessage(msg);
|
||||
@@ -1401,8 +1428,7 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj);
|
||||
break;
|
||||
case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
|
||||
mGatewayStatusCallback.onEnteredSafeMode();
|
||||
mSafeModeTimeoutAlarm = null;
|
||||
handleSafeModeTimeoutExceeded();
|
||||
break;
|
||||
default:
|
||||
logUnhandledMessage(msg);
|
||||
@@ -1432,30 +1458,35 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
buildNetworkCapabilities(mConnectionConfig, mUnderlying);
|
||||
final LinkProperties lp =
|
||||
buildConnectedLinkProperties(mConnectionConfig, tunnelIface, childConfig);
|
||||
final NetworkAgentConfig nac =
|
||||
new NetworkAgentConfig.Builder()
|
||||
.setLegacyType(ConnectivityManager.TYPE_MOBILE)
|
||||
.build();
|
||||
|
||||
final NetworkAgent agent =
|
||||
new NetworkAgent(
|
||||
mVcnContext.getContext(),
|
||||
mVcnContext.getLooper(),
|
||||
mDeps.newNetworkAgent(
|
||||
mVcnContext,
|
||||
TAG,
|
||||
caps,
|
||||
lp,
|
||||
Vcn.getNetworkScore(),
|
||||
new NetworkAgentConfig.Builder().build(),
|
||||
mVcnContext.getVcnNetworkProvider()) {
|
||||
@Override
|
||||
public void onNetworkUnwanted() {
|
||||
Slog.d(TAG, "NetworkAgent was unwanted");
|
||||
teardownAsynchronously();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onValidationStatus(int status, @Nullable Uri redirectUri) {
|
||||
if (status == NetworkAgent.VALIDATION_STATUS_VALID) {
|
||||
clearFailedAttemptCounterAndSafeModeAlarm();
|
||||
}
|
||||
}
|
||||
};
|
||||
nac,
|
||||
mVcnContext.getVcnNetworkProvider(),
|
||||
() -> {
|
||||
Slog.d(TAG, "NetworkAgent was unwanted");
|
||||
// If network agent has already been torn down, skip sending the
|
||||
// disconnect. Unwanted() is always called, even when networkAgents
|
||||
// are unregistered in teardownNetwork(), so prevent duplicate
|
||||
// notifications.
|
||||
if (mNetworkAgent != null) {
|
||||
teardownAsynchronously();
|
||||
}
|
||||
} /* networkUnwantedCallback */,
|
||||
(status) -> {
|
||||
if (status == NetworkAgent.VALIDATION_STATUS_VALID) {
|
||||
clearFailedAttemptCounterAndSafeModeAlarm();
|
||||
}
|
||||
} /* validationStatusCallback */);
|
||||
|
||||
agent.register();
|
||||
agent.markConnected();
|
||||
@@ -1469,6 +1500,11 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
// Validated connection, clear failed attempt counter
|
||||
mFailedAttempts = 0;
|
||||
cancelSafeModeAlarm();
|
||||
|
||||
if (mIsInSafeMode) {
|
||||
mIsInSafeMode = false;
|
||||
mGatewayStatusCallback.onSafeModeStatusChanged();
|
||||
}
|
||||
}
|
||||
|
||||
protected void applyTransform(
|
||||
@@ -1488,13 +1524,6 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
}
|
||||
}
|
||||
|
||||
protected void setupInterface(
|
||||
int token,
|
||||
@NonNull IpSecTunnelInterface tunnelIface,
|
||||
@NonNull VcnChildSessionConfiguration childConfig) {
|
||||
setupInterface(token, tunnelIface, childConfig, null);
|
||||
}
|
||||
|
||||
protected void setupInterface(
|
||||
int token,
|
||||
@NonNull IpSecTunnelInterface tunnelIface,
|
||||
@@ -1579,16 +1608,17 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
transformCreatedInfo.direction);
|
||||
break;
|
||||
case EVENT_SETUP_COMPLETED:
|
||||
final VcnChildSessionConfiguration oldChildConfig = mChildConfig;
|
||||
mChildConfig = ((EventSetupCompletedInfo) msg.obj).childSessionConfig;
|
||||
|
||||
setupInterfaceAndNetworkAgent(mCurrentToken, mTunnelIface, mChildConfig);
|
||||
setupInterfaceAndNetworkAgent(
|
||||
mCurrentToken, mTunnelIface, mChildConfig, oldChildConfig);
|
||||
break;
|
||||
case EVENT_DISCONNECT_REQUESTED:
|
||||
handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj);
|
||||
break;
|
||||
case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
|
||||
mGatewayStatusCallback.onEnteredSafeMode();
|
||||
mSafeModeTimeoutAlarm = null;
|
||||
handleSafeModeTimeoutExceeded();
|
||||
break;
|
||||
default:
|
||||
logUnhandledMessage(msg);
|
||||
@@ -1626,8 +1656,9 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
protected void setupInterfaceAndNetworkAgent(
|
||||
int token,
|
||||
@NonNull IpSecTunnelInterface tunnelIface,
|
||||
@NonNull VcnChildSessionConfiguration childConfig) {
|
||||
setupInterface(token, tunnelIface, childConfig);
|
||||
@NonNull VcnChildSessionConfiguration childConfig,
|
||||
@NonNull VcnChildSessionConfiguration oldChildConfig) {
|
||||
setupInterface(token, tunnelIface, childConfig, oldChildConfig);
|
||||
|
||||
if (mNetworkAgent == null) {
|
||||
mNetworkAgent = buildNetworkAgent(tunnelIface, childConfig);
|
||||
@@ -1692,8 +1723,7 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj);
|
||||
break;
|
||||
case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
|
||||
mGatewayStatusCallback.onEnteredSafeMode();
|
||||
mSafeModeTimeoutAlarm = null;
|
||||
handleSafeModeTimeoutExceeded();
|
||||
break;
|
||||
default:
|
||||
logUnhandledMessage(msg);
|
||||
@@ -1934,6 +1964,16 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
mIkeSession = session;
|
||||
}
|
||||
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
NetworkAgent getNetworkAgent() {
|
||||
return mNetworkAgent;
|
||||
}
|
||||
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
void setNetworkAgent(@Nullable NetworkAgent networkAgent) {
|
||||
mNetworkAgent = networkAgent;
|
||||
}
|
||||
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
void sendDisconnectRequestedAndAcquireWakelock(String reason, boolean shouldQuit) {
|
||||
sendMessageAndAcquireWakeLock(
|
||||
@@ -2018,6 +2058,38 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
return new WakeupMessage(vcnContext.getContext(), handler, tag, runnable);
|
||||
}
|
||||
|
||||
/** Builds a new NetworkAgent. */
|
||||
public NetworkAgent newNetworkAgent(
|
||||
@NonNull VcnContext vcnContext,
|
||||
@NonNull String tag,
|
||||
@NonNull NetworkCapabilities caps,
|
||||
@NonNull LinkProperties lp,
|
||||
@NonNull int score,
|
||||
@NonNull NetworkAgentConfig nac,
|
||||
@NonNull NetworkProvider provider,
|
||||
@NonNull Runnable networkUnwantedCallback,
|
||||
@NonNull Consumer<Integer> validationStatusCallback) {
|
||||
return new NetworkAgent(
|
||||
vcnContext.getContext(),
|
||||
vcnContext.getLooper(),
|
||||
tag,
|
||||
caps,
|
||||
lp,
|
||||
score,
|
||||
nac,
|
||||
provider) {
|
||||
@Override
|
||||
public void onNetworkUnwanted() {
|
||||
networkUnwantedCallback.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onValidationStatus(int status, @Nullable Uri redirectUri) {
|
||||
validationStatusCallback.accept(status);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** Gets the elapsed real time since boot, in millis. */
|
||||
public long getElapsedRealTime() {
|
||||
return SystemClock.elapsedRealtime();
|
||||
|
||||
@@ -536,17 +536,6 @@ public class VcnManagementServiceTest {
|
||||
verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetVcnConfigInSafeModeNotifiesStatusCallback() throws Exception {
|
||||
setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_2, false /* isActive */);
|
||||
mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME);
|
||||
verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE);
|
||||
|
||||
mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
|
||||
|
||||
verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClearVcnConfigRequiresNonSystemServer() throws Exception {
|
||||
doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid();
|
||||
@@ -902,7 +891,9 @@ public class VcnManagementServiceTest {
|
||||
}
|
||||
|
||||
private void triggerVcnSafeMode(
|
||||
@NonNull ParcelUuid subGroup, @NonNull TelephonySubscriptionSnapshot snapshot)
|
||||
@NonNull ParcelUuid subGroup,
|
||||
@NonNull TelephonySubscriptionSnapshot snapshot,
|
||||
boolean isInSafeMode)
|
||||
throws Exception {
|
||||
verify(mMockDeps)
|
||||
.newVcn(
|
||||
@@ -913,22 +904,32 @@ public class VcnManagementServiceTest {
|
||||
mVcnCallbackCaptor.capture());
|
||||
|
||||
VcnCallback vcnCallback = mVcnCallbackCaptor.getValue();
|
||||
vcnCallback.onEnteredSafeMode();
|
||||
vcnCallback.onSafeModeStatusChanged(isInSafeMode);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVcnEnteringSafeModeNotifiesPolicyListeners() throws Exception {
|
||||
private void verifyVcnSafeModeChangesNotifiesPolicyListeners(boolean enterSafeMode)
|
||||
throws Exception {
|
||||
TelephonySubscriptionSnapshot snapshot =
|
||||
triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1));
|
||||
|
||||
mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
|
||||
|
||||
triggerVcnSafeMode(TEST_UUID_1, snapshot);
|
||||
triggerVcnSafeMode(TEST_UUID_1, snapshot, enterSafeMode);
|
||||
|
||||
verify(mMockPolicyListener).onPolicyChanged();
|
||||
}
|
||||
|
||||
private void triggerVcnStatusCallbackOnEnteredSafeMode(
|
||||
@Test
|
||||
public void testVcnEnteringSafeModeNotifiesPolicyListeners() throws Exception {
|
||||
verifyVcnSafeModeChangesNotifiesPolicyListeners(true /* enterSafeMode */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVcnExitingSafeModeNotifiesPolicyListeners() throws Exception {
|
||||
verifyVcnSafeModeChangesNotifiesPolicyListeners(false /* enterSafeMode */);
|
||||
}
|
||||
|
||||
private void triggerVcnStatusCallbackOnSafeModeStatusChanged(
|
||||
@NonNull ParcelUuid subGroup,
|
||||
@NonNull String pkgName,
|
||||
int uid,
|
||||
@@ -951,12 +952,13 @@ public class VcnManagementServiceTest {
|
||||
|
||||
mVcnMgmtSvc.registerVcnStatusCallback(subGroup, mMockStatusCallback, pkgName);
|
||||
|
||||
triggerVcnSafeMode(subGroup, snapshot);
|
||||
triggerVcnSafeMode(subGroup, snapshot, true /* enterSafeMode */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVcnStatusCallbackOnEnteredSafeModeWithCarrierPrivileges() throws Exception {
|
||||
triggerVcnStatusCallbackOnEnteredSafeMode(
|
||||
public void testVcnStatusCallbackOnSafeModeStatusChangedWithCarrierPrivileges()
|
||||
throws Exception {
|
||||
triggerVcnStatusCallbackOnSafeModeStatusChanged(
|
||||
TEST_UUID_1,
|
||||
TEST_PACKAGE_NAME,
|
||||
TEST_UID,
|
||||
@@ -967,8 +969,9 @@ public class VcnManagementServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVcnStatusCallbackOnEnteredSafeModeWithoutCarrierPrivileges() throws Exception {
|
||||
triggerVcnStatusCallbackOnEnteredSafeMode(
|
||||
public void testVcnStatusCallbackOnSafeModeStatusChangedWithoutCarrierPrivileges()
|
||||
throws Exception {
|
||||
triggerVcnStatusCallbackOnSafeModeStatusChanged(
|
||||
TEST_UUID_1,
|
||||
TEST_PACKAGE_NAME,
|
||||
TEST_UID,
|
||||
@@ -980,8 +983,9 @@ public class VcnManagementServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVcnStatusCallbackOnEnteredSafeModeWithoutLocationPermission() throws Exception {
|
||||
triggerVcnStatusCallbackOnEnteredSafeMode(
|
||||
public void testVcnStatusCallbackOnSafeModeStatusChangedWithoutLocationPermission()
|
||||
throws Exception {
|
||||
triggerVcnStatusCallbackOnSafeModeStatusChanged(
|
||||
TEST_UUID_1,
|
||||
TEST_PACKAGE_NAME,
|
||||
TEST_UID,
|
||||
|
||||
@@ -32,6 +32,7 @@ import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Matchers.argThat;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
@@ -40,6 +41,8 @@ import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.LinkAddress;
|
||||
import android.net.LinkProperties;
|
||||
import android.net.NetworkAgent;
|
||||
import android.net.NetworkCapabilities;
|
||||
@@ -58,19 +61,29 @@ import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/** Tests for VcnGatewayConnection.ConnectedState */
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnectionTestBase {
|
||||
private VcnIkeSession mIkeSession;
|
||||
private NetworkAgent mNetworkAgent;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
mNetworkAgent = mock(NetworkAgent.class);
|
||||
doReturn(mNetworkAgent)
|
||||
.when(mDeps)
|
||||
.newNetworkAgent(any(), any(), any(), any(), anyInt(), any(), any(), any(), any());
|
||||
|
||||
mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1);
|
||||
|
||||
mIkeSession = mGatewayConnection.buildIkeSession(TEST_UNDERLYING_NETWORK_RECORD_1.network);
|
||||
@@ -159,21 +172,44 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
|
||||
assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChildOpenedRegistersNetwork() throws Exception {
|
||||
// Verify scheduled but not canceled when entering ConnectedState
|
||||
verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
|
||||
private void triggerChildOpened() {
|
||||
triggerChildOpened(Collections.singletonList(TEST_INTERNAL_ADDR), TEST_DNS_ADDR);
|
||||
}
|
||||
|
||||
private void triggerChildOpened(List<LinkAddress> internalAddresses, InetAddress dnsAddress) {
|
||||
final VcnChildSessionConfiguration mMockChildSessionConfig =
|
||||
mock(VcnChildSessionConfiguration.class);
|
||||
doReturn(Collections.singletonList(TEST_INTERNAL_ADDR))
|
||||
.when(mMockChildSessionConfig)
|
||||
.getInternalAddresses();
|
||||
doReturn(Collections.singletonList(TEST_DNS_ADDR))
|
||||
doReturn(internalAddresses).when(mMockChildSessionConfig).getInternalAddresses();
|
||||
doReturn(Collections.singletonList(dnsAddress))
|
||||
.when(mMockChildSessionConfig)
|
||||
.getInternalDnsServers();
|
||||
|
||||
getChildSessionCallback().onOpened(mMockChildSessionConfig);
|
||||
}
|
||||
|
||||
private void triggerValidation(int status) {
|
||||
final ArgumentCaptor<Consumer<Integer>> validationCallbackCaptor =
|
||||
ArgumentCaptor.forClass(Consumer.class);
|
||||
verify(mDeps)
|
||||
.newNetworkAgent(
|
||||
any(),
|
||||
any(),
|
||||
any(),
|
||||
any(),
|
||||
anyInt(),
|
||||
any(),
|
||||
any(),
|
||||
any(),
|
||||
validationCallbackCaptor.capture());
|
||||
|
||||
validationCallbackCaptor.getValue().accept(status);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChildOpenedRegistersNetwork() throws Exception {
|
||||
// Verify scheduled but not canceled when entering ConnectedState
|
||||
verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
|
||||
triggerChildOpened();
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
|
||||
@@ -182,15 +218,20 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
|
||||
ArgumentCaptor.forClass(LinkProperties.class);
|
||||
final ArgumentCaptor<NetworkCapabilities> ncCaptor =
|
||||
ArgumentCaptor.forClass(NetworkCapabilities.class);
|
||||
verify(mConnMgr)
|
||||
.registerNetworkAgent(
|
||||
any(),
|
||||
any(),
|
||||
lpCaptor.capture(),
|
||||
verify(mDeps)
|
||||
.newNetworkAgent(
|
||||
eq(mVcnContext),
|
||||
any(String.class),
|
||||
ncCaptor.capture(),
|
||||
lpCaptor.capture(),
|
||||
anyInt(),
|
||||
argThat(nac -> nac.getLegacyType() == ConnectivityManager.TYPE_MOBILE),
|
||||
any(),
|
||||
any(),
|
||||
anyInt());
|
||||
any());
|
||||
verify(mNetworkAgent).register();
|
||||
verify(mNetworkAgent).markConnected();
|
||||
|
||||
verify(mIpSecSvc)
|
||||
.addAddressToTunnelInterface(
|
||||
eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(TEST_INTERNAL_ADDR), any());
|
||||
@@ -208,9 +249,78 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
|
||||
|
||||
// Now that Vcn Network is up, notify it as validated and verify the SafeMode alarm is
|
||||
// canceled
|
||||
mGatewayConnection.mNetworkAgent.onValidationStatus(
|
||||
NetworkAgent.VALIDATION_STATUS_VALID, null /* redirectUri */);
|
||||
triggerValidation(NetworkAgent.VALIDATION_STATUS_VALID);
|
||||
verify(mSafeModeTimeoutAlarm).cancel();
|
||||
assertFalse(mGatewayConnection.isInSafeMode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInternalAndDnsAddressesChanged() throws Exception {
|
||||
final List<LinkAddress> startingInternalAddrs =
|
||||
Arrays.asList(new LinkAddress[] {TEST_INTERNAL_ADDR, TEST_INTERNAL_ADDR_2});
|
||||
triggerChildOpened(startingInternalAddrs, TEST_DNS_ADDR);
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
for (LinkAddress addr : startingInternalAddrs) {
|
||||
verify(mIpSecSvc)
|
||||
.addAddressToTunnelInterface(
|
||||
eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(addr), any());
|
||||
}
|
||||
|
||||
verify(mDeps)
|
||||
.newNetworkAgent(
|
||||
any(),
|
||||
any(),
|
||||
any(),
|
||||
argThat(
|
||||
lp ->
|
||||
startingInternalAddrs.equals(lp.getLinkAddresses())
|
||||
&& Collections.singletonList(TEST_DNS_ADDR)
|
||||
.equals(lp.getDnsServers())),
|
||||
anyInt(),
|
||||
any(),
|
||||
any(),
|
||||
any(),
|
||||
any());
|
||||
|
||||
// Trigger another connection event, and verify that the addresses change
|
||||
final List<LinkAddress> newInternalAddrs =
|
||||
Arrays.asList(new LinkAddress[] {TEST_INTERNAL_ADDR_2, TEST_INTERNAL_ADDR_3});
|
||||
triggerChildOpened(newInternalAddrs, TEST_DNS_ADDR_2);
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
// Verify addresses on tunnel network added/removed
|
||||
for (LinkAddress addr : newInternalAddrs) {
|
||||
verify(mIpSecSvc)
|
||||
.addAddressToTunnelInterface(
|
||||
eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(addr), any());
|
||||
}
|
||||
verify(mIpSecSvc)
|
||||
.removeAddressFromTunnelInterface(
|
||||
eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(TEST_INTERNAL_ADDR), any());
|
||||
|
||||
// TODO(b/184579891): Also verify link properties updated and sent when sendLinkProperties
|
||||
// is mockable
|
||||
|
||||
// Verify that IpSecTunnelInterface only created once
|
||||
verify(mIpSecSvc).createTunnelInterface(any(), any(), any(), any(), any());
|
||||
verifyNoMoreInteractions(mIpSecSvc);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccessfulConnectionExitsSafeMode() throws Exception {
|
||||
verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent(
|
||||
mGatewayConnection.mConnectedState);
|
||||
|
||||
assertTrue(mGatewayConnection.isInSafeMode());
|
||||
assertFalse(mGatewayConnection.isQuitting());
|
||||
|
||||
triggerChildOpened();
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
triggerValidation(NetworkAgent.VALIDATION_STATUS_VALID);
|
||||
|
||||
assertFalse(mGatewayConnection.isInSafeMode());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -118,8 +118,9 @@ public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectio
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSafeModeTimeoutNotifiesCallback() {
|
||||
verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mConnectingState);
|
||||
public void testSafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent() {
|
||||
verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent(
|
||||
mGatewayConnection.mConnectingState);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -86,8 +86,9 @@ public class VcnGatewayConnectionDisconnectingStateTest extends VcnGatewayConnec
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSafeModeTimeoutNotifiesCallback() {
|
||||
verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mDisconnectingState);
|
||||
public void testSafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent() {
|
||||
verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent(
|
||||
mGatewayConnection.mDisconnectingState);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -96,8 +96,9 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSafeModeTimeoutNotifiesCallback() {
|
||||
verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mRetryTimeoutState);
|
||||
public void testSafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent() {
|
||||
verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent(
|
||||
mGatewayConnection.mRetryTimeoutState);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -21,6 +21,8 @@ import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession;
|
||||
import static com.android.server.vcn.VcnTestUtils.setupIpSecManager;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
@@ -42,6 +44,7 @@ import android.net.IpSecTunnelInterfaceResponse;
|
||||
import android.net.LinkAddress;
|
||||
import android.net.LinkProperties;
|
||||
import android.net.Network;
|
||||
import android.net.NetworkAgent;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.ipsec.ike.ChildSessionCallback;
|
||||
import android.net.ipsec.ike.IkeSessionCallback;
|
||||
@@ -71,8 +74,14 @@ public class VcnGatewayConnectionTestBase {
|
||||
protected static final ParcelUuid TEST_SUB_GRP = new ParcelUuid(UUID.randomUUID());
|
||||
protected static final InetAddress TEST_DNS_ADDR =
|
||||
InetAddresses.parseNumericAddress("2001:DB8:0:1::");
|
||||
protected static final InetAddress TEST_DNS_ADDR_2 =
|
||||
InetAddresses.parseNumericAddress("2001:DB8:0:2::");
|
||||
protected static final LinkAddress TEST_INTERNAL_ADDR =
|
||||
new LinkAddress(InetAddresses.parseNumericAddress("2001:DB8:0:2::"), 64);
|
||||
new LinkAddress(InetAddresses.parseNumericAddress("2001:DB8:1:1::"), 64);
|
||||
protected static final LinkAddress TEST_INTERNAL_ADDR_2 =
|
||||
new LinkAddress(InetAddresses.parseNumericAddress("2001:DB8:1:2::"), 64);
|
||||
protected static final LinkAddress TEST_INTERNAL_ADDR_3 =
|
||||
new LinkAddress(InetAddresses.parseNumericAddress("2001:DB8:1:3::"), 64);
|
||||
|
||||
protected static final int TEST_IPSEC_SPI_VALUE = 0x1234;
|
||||
protected static final int TEST_IPSEC_SPI_RESOURCE_ID = 1;
|
||||
@@ -267,7 +276,12 @@ public class VcnGatewayConnectionTestBase {
|
||||
expectCanceled);
|
||||
}
|
||||
|
||||
protected void verifySafeModeTimeoutNotifiesCallback(@NonNull State expectedState) {
|
||||
protected void verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent(
|
||||
@NonNull State expectedState) {
|
||||
// Set a NetworkAgent, and expect it to be unregistered and cleared
|
||||
final NetworkAgent mockNetworkAgent = mock(NetworkAgent.class);
|
||||
mGatewayConnection.setNetworkAgent(mockNetworkAgent);
|
||||
|
||||
// SafeMode timer starts when VcnGatewayConnection exits DisconnectedState (the initial
|
||||
// state)
|
||||
final Runnable delayedEvent =
|
||||
@@ -275,7 +289,11 @@ public class VcnGatewayConnectionTestBase {
|
||||
delayedEvent.run();
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
verify(mGatewayStatusCallback).onEnteredSafeMode();
|
||||
verify(mGatewayStatusCallback).onSafeModeStatusChanged();
|
||||
assertEquals(expectedState, mGatewayConnection.getCurrentState());
|
||||
assertTrue(mGatewayConnection.isInSafeMode());
|
||||
|
||||
verify(mockNetworkAgent).unregister();
|
||||
assertNull(mGatewayConnection.getNetworkAgent());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,14 +19,13 @@ 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 android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
|
||||
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
|
||||
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE;
|
||||
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.argThat;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
@@ -54,7 +53,6 @@ import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
@@ -136,6 +134,7 @@ public class VcnTest {
|
||||
private void startVcnGatewayWithCapabilities(
|
||||
NetworkRequestListener requestListener, int... netCapabilities) {
|
||||
final NetworkRequest.Builder requestBuilder = new NetworkRequest.Builder();
|
||||
requestBuilder.addTransportType(TRANSPORT_CELLULAR);
|
||||
for (final int netCapability : netCapabilities) {
|
||||
requestBuilder.addCapability(netCapability);
|
||||
}
|
||||
@@ -160,8 +159,7 @@ public class VcnTest {
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
for (final VcnGatewayConnection gateway : gatewayConnections) {
|
||||
verify(gateway, status == VCN_STATUS_CODE_ACTIVE ? times(1) : never())
|
||||
.updateSubscriptionSnapshot(eq(updatedSnapshot));
|
||||
verify(gateway).updateSubscriptionSnapshot(eq(updatedSnapshot));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,32 +200,53 @@ public class VcnTest {
|
||||
|
||||
private void verifySafeMode(
|
||||
NetworkRequestListener requestListener,
|
||||
Set<VcnGatewayConnection> expectedGatewaysTornDown) {
|
||||
assertEquals(VCN_STATUS_CODE_SAFE_MODE, mVcn.getStatus());
|
||||
for (final VcnGatewayConnection gatewayConnection : expectedGatewaysTornDown) {
|
||||
verify(gatewayConnection).teardownAsynchronously();
|
||||
Set<VcnGatewayConnection> activeGateways,
|
||||
boolean expectInSafeMode) {
|
||||
for (VcnGatewayConnection gatewayConnection : activeGateways) {
|
||||
verify(gatewayConnection, never()).teardownAsynchronously();
|
||||
}
|
||||
verify(mVcnNetworkProvider).unregisterListener(requestListener);
|
||||
verify(mVcnCallback).onEnteredSafeMode();
|
||||
|
||||
assertEquals(
|
||||
expectInSafeMode ? VCN_STATUS_CODE_SAFE_MODE : VCN_STATUS_CODE_ACTIVE,
|
||||
mVcn.getStatus());
|
||||
verify(mVcnCallback).onSafeModeStatusChanged(expectInSafeMode);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGatewayEnteringSafeModeNotifiesVcn() {
|
||||
public void testGatewayEnteringAndExitingSafeModeNotifiesVcn() {
|
||||
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
|
||||
// Doesn't matter which callback this gets, or which VCN is in safe mode - any Gateway
|
||||
// entering Safemode should trigger safe mode
|
||||
final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue();
|
||||
statusCallback.onEnteredSafeMode();
|
||||
final VcnGatewayConnection gatewayConnection = gatewayConnections.iterator().next();
|
||||
|
||||
doReturn(true).when(gatewayConnection).isInSafeMode();
|
||||
statusCallback.onSafeModeStatusChanged();
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
verifySafeMode(requestListener, gatewayConnections);
|
||||
verifySafeMode(requestListener, gatewayConnections, true /* expectInSafeMode */);
|
||||
|
||||
// Verify that when all GatewayConnections exit safe mode, the VCN also exits safe mode
|
||||
doReturn(false).when(gatewayConnection).isInSafeMode();
|
||||
statusCallback.onSafeModeStatusChanged();
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
verifySafeMode(requestListener, gatewayConnections, false /* expectInSafeMode */);
|
||||
|
||||
// Re-trigger, verify safe mode callback does not get fired again for identical state
|
||||
statusCallback.onSafeModeStatusChanged();
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
// Expect only once still; from above.
|
||||
verify(mVcnCallback).onSafeModeStatusChanged(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGatewayQuit() {
|
||||
private void verifyGatewayQuit(int status) {
|
||||
mVcn.setStatus(status);
|
||||
|
||||
final NetworkRequestListener requestListener = verifyAndGetRequestListener();
|
||||
final Set<VcnGatewayConnection> gatewayConnections =
|
||||
new ArraySet<>(startGatewaysAndGetGatewayConnections(requestListener));
|
||||
@@ -240,7 +259,7 @@ public class VcnTest {
|
||||
assertEquals(1, mVcn.getVcnGatewayConnections().size());
|
||||
verify(mVcnNetworkProvider).resendAllRequests(requestListener);
|
||||
|
||||
// Verify that the VcnGatewayConnection is restarted
|
||||
// Verify that the VcnGatewayConnection is restarted if a request exists for it
|
||||
triggerVcnRequestListeners(requestListener);
|
||||
mTestLooper.dispatchAll();
|
||||
assertEquals(2, mVcn.getVcnGatewayConnections().size());
|
||||
@@ -254,21 +273,13 @@ public class VcnTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGatewayQuitWhileInactive() {
|
||||
final NetworkRequestListener requestListener = verifyAndGetRequestListener();
|
||||
final Set<VcnGatewayConnection> gatewayConnections =
|
||||
new ArraySet<>(startGatewaysAndGetGatewayConnections(requestListener));
|
||||
public void testGatewayQuitReevaluatesRequests() {
|
||||
verifyGatewayQuit(VCN_STATUS_CODE_ACTIVE);
|
||||
}
|
||||
|
||||
mVcn.teardownAsynchronously();
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
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, never()).resendAllRequests(requestListener);
|
||||
@Test
|
||||
public void testGatewayQuitReevaluatesRequestsInSafeMode() {
|
||||
verifyGatewayQuit(VCN_STATUS_CODE_SAFE_MODE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -298,49 +309,4 @@ public class VcnTest {
|
||||
verify(removedGatewayConnection).teardownAsynchronously();
|
||||
verify(mVcnNetworkProvider).resendAllRequests(requestListener);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateConfigExitsSafeMode() {
|
||||
final NetworkRequestListener requestListener = verifyAndGetRequestListener();
|
||||
final Set<VcnGatewayConnection> gatewayConnections =
|
||||
new ArraySet<>(startGatewaysAndGetGatewayConnections(requestListener));
|
||||
|
||||
final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue();
|
||||
statusCallback.onEnteredSafeMode();
|
||||
mTestLooper.dispatchAll();
|
||||
verifySafeMode(requestListener, gatewayConnections);
|
||||
|
||||
doAnswer(invocation -> {
|
||||
final NetworkRequestListener listener = invocation.getArgument(0);
|
||||
triggerVcnRequestListeners(listener);
|
||||
return null;
|
||||
}).when(mVcnNetworkProvider).registerListener(eq(requestListener));
|
||||
|
||||
mVcn.updateConfig(mConfig);
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
// Registered on start, then re-registered with new configs
|
||||
verify(mVcnNetworkProvider, times(2)).registerListener(eq(requestListener));
|
||||
assertEquals(VCN_STATUS_CODE_ACTIVE, mVcn.getStatus());
|
||||
for (final int[] caps : TEST_CAPS) {
|
||||
// Expect each gateway connection created only on initial startup
|
||||
verify(mDeps)
|
||||
.newVcnGatewayConnection(
|
||||
eq(mVcnContext),
|
||||
eq(TEST_SUB_GROUP),
|
||||
eq(mSubscriptionSnapshot),
|
||||
argThat(config -> Arrays.equals(caps, config.getExposedCapabilities())),
|
||||
any());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIgnoreNetworkRequestWhileInactive() {
|
||||
mVcn.setStatus(VCN_STATUS_CODE_INACTIVE);
|
||||
|
||||
final NetworkRequestListener requestListener = verifyAndGetRequestListener();
|
||||
triggerVcnRequestListeners(requestListener);
|
||||
|
||||
verify(mDeps, never()).newVcnGatewayConnection(any(), any(), any(), any(), any());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user