Disable INTERNET/DUN when mobile data toggled off
This change disables INTERNET and DUN capabilities once the mobile data
toggle is turned off. Additionally, when the toggle is flipped, any
existing networks advertising either of those two capabilities will be
restarted in order to remove the capabilities.
Bug: 184864726
Test: atest FrameworksVcnTests
Merged-In: I81efeaa4b129443b08a597ff45e0037ddefeb414
Change-Id: I81efeaa4b129443b08a597ff45e0037ddefeb414
(cherry picked from commit fcacb06752)
This commit is contained in:
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
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_NOT_VCN_MANAGED;
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
|
||||||
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
|
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_ACTIVE;
|
||||||
@@ -26,14 +28,20 @@ import static com.android.server.VcnManagementService.VDBG;
|
|||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.database.ContentObserver;
|
||||||
import android.net.NetworkCapabilities;
|
import android.net.NetworkCapabilities;
|
||||||
import android.net.NetworkRequest;
|
import android.net.NetworkRequest;
|
||||||
|
import android.net.Uri;
|
||||||
import android.net.vcn.VcnConfig;
|
import android.net.vcn.VcnConfig;
|
||||||
import android.net.vcn.VcnGatewayConnectionConfig;
|
import android.net.vcn.VcnGatewayConnectionConfig;
|
||||||
import android.net.vcn.VcnManager.VcnErrorCode;
|
import android.net.vcn.VcnManager.VcnErrorCode;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.ParcelUuid;
|
import android.os.ParcelUuid;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import android.telephony.TelephonyManager;
|
||||||
|
import android.util.ArraySet;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
@@ -42,9 +50,11 @@ import com.android.internal.util.IndentingPrintWriter;
|
|||||||
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;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@@ -61,6 +71,9 @@ import java.util.Set;
|
|||||||
public class Vcn extends Handler {
|
public class Vcn extends Handler {
|
||||||
private static final String TAG = Vcn.class.getSimpleName();
|
private static final String TAG = Vcn.class.getSimpleName();
|
||||||
|
|
||||||
|
private static final List<Integer> CAPS_REQUIRING_MOBILE_DATA =
|
||||||
|
Arrays.asList(NET_CAPABILITY_INTERNET, NET_CAPABILITY_DUN);
|
||||||
|
|
||||||
private static final int MSG_EVENT_BASE = 0;
|
private static final int MSG_EVENT_BASE = 0;
|
||||||
private static final int MSG_CMD_BASE = 100;
|
private static final int MSG_CMD_BASE = 100;
|
||||||
|
|
||||||
@@ -110,6 +123,15 @@ public class Vcn extends Handler {
|
|||||||
*/
|
*/
|
||||||
private static final int MSG_EVENT_SAFE_MODE_STATE_CHANGED = MSG_EVENT_BASE + 4;
|
private static final int MSG_EVENT_SAFE_MODE_STATE_CHANGED = MSG_EVENT_BASE + 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers reevaluation of mobile data enabled conditions.
|
||||||
|
*
|
||||||
|
* <p>Upon this notification, the VCN will check if any of the underlying subIds have mobile
|
||||||
|
* data enabled. If not, the VCN will restart any GatewayConnections providing INTERNET or DUN
|
||||||
|
* with the current mobile data toggle status.
|
||||||
|
*/
|
||||||
|
private static final int MSG_EVENT_MOBILE_DATA_TOGGLED = MSG_EVENT_BASE + 5;
|
||||||
|
|
||||||
/** 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;
|
||||||
|
|
||||||
@@ -118,6 +140,8 @@ public class Vcn extends Handler {
|
|||||||
@NonNull private final Dependencies mDeps;
|
@NonNull private final Dependencies mDeps;
|
||||||
@NonNull private final VcnNetworkRequestListener mRequestListener;
|
@NonNull private final VcnNetworkRequestListener mRequestListener;
|
||||||
@NonNull private final VcnCallback mVcnCallback;
|
@NonNull private final VcnCallback mVcnCallback;
|
||||||
|
@NonNull private final VcnContentResolver mContentResolver;
|
||||||
|
@NonNull private final ContentObserver mMobileDataSettingsObserver;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map containing all VcnGatewayConnections and their VcnGatewayConnectionConfigs.
|
* Map containing all VcnGatewayConnections and their VcnGatewayConnectionConfigs.
|
||||||
@@ -154,6 +178,8 @@ public class Vcn extends Handler {
|
|||||||
// Accessed from different threads, but always under lock in VcnManagementService
|
// Accessed from different threads, but always under lock in VcnManagementService
|
||||||
private volatile int mCurrentStatus = VCN_STATUS_CODE_ACTIVE;
|
private volatile int mCurrentStatus = VCN_STATUS_CODE_ACTIVE;
|
||||||
|
|
||||||
|
private boolean mIsMobileDataEnabled = false;
|
||||||
|
|
||||||
public Vcn(
|
public Vcn(
|
||||||
@NonNull VcnContext vcnContext,
|
@NonNull VcnContext vcnContext,
|
||||||
@NonNull ParcelUuid subscriptionGroup,
|
@NonNull ParcelUuid subscriptionGroup,
|
||||||
@@ -177,10 +203,19 @@ public class Vcn extends Handler {
|
|||||||
mVcnCallback = Objects.requireNonNull(vcnCallback, "Missing vcnCallback");
|
mVcnCallback = Objects.requireNonNull(vcnCallback, "Missing vcnCallback");
|
||||||
mDeps = Objects.requireNonNull(deps, "Missing deps");
|
mDeps = Objects.requireNonNull(deps, "Missing deps");
|
||||||
mRequestListener = new VcnNetworkRequestListener();
|
mRequestListener = new VcnNetworkRequestListener();
|
||||||
|
mContentResolver = mDeps.newVcnContentResolver(mVcnContext);
|
||||||
|
mMobileDataSettingsObserver = new VcnMobileDataContentObserver(this /* handler */);
|
||||||
|
|
||||||
|
final Uri uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA);
|
||||||
|
mContentResolver.registerContentObserver(
|
||||||
|
uri, true /* notifyForDescendants */, mMobileDataSettingsObserver);
|
||||||
|
|
||||||
mConfig = Objects.requireNonNull(config, "Missing config");
|
mConfig = Objects.requireNonNull(config, "Missing config");
|
||||||
mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot");
|
mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot");
|
||||||
|
|
||||||
|
// Update mIsMobileDataEnabled before starting handling of NetworkRequests.
|
||||||
|
mIsMobileDataEnabled = getMobileDataStatus();
|
||||||
|
|
||||||
// Register to receive cached and future NetworkRequests
|
// Register to receive cached and future NetworkRequests
|
||||||
mVcnContext.getVcnNetworkProvider().registerListener(mRequestListener);
|
mVcnContext.getVcnNetworkProvider().registerListener(mRequestListener);
|
||||||
}
|
}
|
||||||
@@ -260,6 +295,9 @@ public class Vcn extends Handler {
|
|||||||
case MSG_EVENT_SAFE_MODE_STATE_CHANGED:
|
case MSG_EVENT_SAFE_MODE_STATE_CHANGED:
|
||||||
handleSafeModeStatusChanged();
|
handleSafeModeStatusChanged();
|
||||||
break;
|
break;
|
||||||
|
case MSG_EVENT_MOBILE_DATA_TOGGLED:
|
||||||
|
handleMobileDataToggled();
|
||||||
|
break;
|
||||||
case MSG_CMD_TEARDOWN:
|
case MSG_CMD_TEARDOWN:
|
||||||
handleTeardown();
|
handleTeardown();
|
||||||
break;
|
break;
|
||||||
@@ -366,18 +404,37 @@ public class Vcn extends Handler {
|
|||||||
if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
|
if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
|
||||||
Slog.v(getLogTag(), "Bringing up new VcnGatewayConnection for request " + request);
|
Slog.v(getLogTag(), "Bringing up new VcnGatewayConnection for request " + request);
|
||||||
|
|
||||||
|
if (getExposedCapabilitiesForMobileDataState(gatewayConnectionConfig).isEmpty()) {
|
||||||
|
// Skip; this network does not provide any services if mobile data is disabled.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
final VcnGatewayConnection vcnGatewayConnection =
|
final VcnGatewayConnection vcnGatewayConnection =
|
||||||
mDeps.newVcnGatewayConnection(
|
mDeps.newVcnGatewayConnection(
|
||||||
mVcnContext,
|
mVcnContext,
|
||||||
mSubscriptionGroup,
|
mSubscriptionGroup,
|
||||||
mLastSnapshot,
|
mLastSnapshot,
|
||||||
gatewayConnectionConfig,
|
gatewayConnectionConfig,
|
||||||
new VcnGatewayStatusCallbackImpl(gatewayConnectionConfig));
|
new VcnGatewayStatusCallbackImpl(gatewayConnectionConfig),
|
||||||
|
mIsMobileDataEnabled);
|
||||||
mVcnGatewayConnections.put(gatewayConnectionConfig, vcnGatewayConnection);
|
mVcnGatewayConnections.put(gatewayConnectionConfig, vcnGatewayConnection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Set<Integer> getExposedCapabilitiesForMobileDataState(
|
||||||
|
VcnGatewayConnectionConfig gatewayConnectionConfig) {
|
||||||
|
if (mIsMobileDataEnabled) {
|
||||||
|
return gatewayConnectionConfig.getAllExposedCapabilities();
|
||||||
|
}
|
||||||
|
|
||||||
|
final Set<Integer> exposedCapsWithoutMobileData =
|
||||||
|
new ArraySet<>(gatewayConnectionConfig.getAllExposedCapabilities());
|
||||||
|
exposedCapsWithoutMobileData.removeAll(CAPS_REQUIRING_MOBILE_DATA);
|
||||||
|
|
||||||
|
return exposedCapsWithoutMobileData;
|
||||||
|
}
|
||||||
|
|
||||||
private void handleGatewayConnectionQuit(VcnGatewayConnectionConfig config) {
|
private void handleGatewayConnectionQuit(VcnGatewayConnectionConfig config) {
|
||||||
Slog.v(getLogTag(), "VcnGatewayConnection quit: " + config);
|
Slog.v(getLogTag(), "VcnGatewayConnection quit: " + config);
|
||||||
mVcnGatewayConnections.remove(config);
|
mVcnGatewayConnections.remove(config);
|
||||||
@@ -396,12 +453,55 @@ public class Vcn extends Handler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleMobileDataToggled() {
|
||||||
|
final boolean oldMobileDataEnabledStatus = mIsMobileDataEnabled;
|
||||||
|
mIsMobileDataEnabled = getMobileDataStatus();
|
||||||
|
|
||||||
|
if (oldMobileDataEnabledStatus != mIsMobileDataEnabled) {
|
||||||
|
// Teardown any GatewayConnections that advertise INTERNET or DUN. If they provide other
|
||||||
|
// services, the VcnGatewayConnections will be restarted without advertising INTERNET or
|
||||||
|
// DUN.
|
||||||
|
for (Entry<VcnGatewayConnectionConfig, VcnGatewayConnection> entry :
|
||||||
|
mVcnGatewayConnections.entrySet()) {
|
||||||
|
final VcnGatewayConnectionConfig gatewayConnectionConfig = entry.getKey();
|
||||||
|
final VcnGatewayConnection gatewayConnection = entry.getValue();
|
||||||
|
|
||||||
|
final Set<Integer> exposedCaps =
|
||||||
|
gatewayConnectionConfig.getAllExposedCapabilities();
|
||||||
|
if (exposedCaps.contains(NET_CAPABILITY_INTERNET)
|
||||||
|
|| exposedCaps.contains(NET_CAPABILITY_DUN)) {
|
||||||
|
if (gatewayConnection == null) {
|
||||||
|
Slog.wtf(
|
||||||
|
getLogTag(),
|
||||||
|
"Found gatewayConnectionConfig without GatewayConnection");
|
||||||
|
} else {
|
||||||
|
// TODO(b/184868850): Optimize by restarting NetworkAgents without teardown.
|
||||||
|
gatewayConnection.teardownAsynchronously();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean getMobileDataStatus() {
|
||||||
|
final TelephonyManager genericTelMan =
|
||||||
|
mVcnContext.getContext().getSystemService(TelephonyManager.class);
|
||||||
|
|
||||||
|
for (int subId : mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) {
|
||||||
|
if (genericTelMan.createForSubscriptionId(subId).isDataEnabled()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isRequestSatisfiedByGatewayConnectionConfig(
|
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.addTransportType(TRANSPORT_CELLULAR);
|
builder.addTransportType(TRANSPORT_CELLULAR);
|
||||||
builder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
|
builder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
|
||||||
for (int cap : config.getAllExposedCapabilities()) {
|
for (int cap : getExposedCapabilitiesForMobileDataState(config)) {
|
||||||
builder.addCapability(cap);
|
builder.addCapability(cap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -432,6 +532,16 @@ public class Vcn extends Handler {
|
|||||||
pw.decreaseIndent();
|
pw.decreaseIndent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||||
|
public boolean isMobileDataEnabled() {
|
||||||
|
return mIsMobileDataEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||||
|
public void setMobileDataEnabled(boolean isMobileDataEnabled) {
|
||||||
|
mIsMobileDataEnabled = isMobileDataEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
/** Retrieves the network score for a VCN Network */
|
/** Retrieves the network score for a VCN Network */
|
||||||
// Package visibility for use in VcnGatewayConnection
|
// Package visibility for use in VcnGatewayConnection
|
||||||
static int getNetworkScore() {
|
static int getNetworkScore() {
|
||||||
@@ -485,6 +595,17 @@ public class Vcn extends Handler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class VcnMobileDataContentObserver extends ContentObserver {
|
||||||
|
private VcnMobileDataContentObserver(Handler handler) {
|
||||||
|
super(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChange(boolean selfChange) {
|
||||||
|
sendMessage(obtainMessage(MSG_EVENT_MOBILE_DATA_TOGGLED));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** External dependencies used by Vcn, for injection in tests */
|
/** External dependencies used by Vcn, for injection in tests */
|
||||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||||
public static class Dependencies {
|
public static class Dependencies {
|
||||||
@@ -494,13 +615,36 @@ public class Vcn extends Handler {
|
|||||||
ParcelUuid subscriptionGroup,
|
ParcelUuid subscriptionGroup,
|
||||||
TelephonySubscriptionSnapshot snapshot,
|
TelephonySubscriptionSnapshot snapshot,
|
||||||
VcnGatewayConnectionConfig connectionConfig,
|
VcnGatewayConnectionConfig connectionConfig,
|
||||||
VcnGatewayStatusCallback gatewayStatusCallback) {
|
VcnGatewayStatusCallback gatewayStatusCallback,
|
||||||
|
boolean isMobileDataEnabled) {
|
||||||
return new VcnGatewayConnection(
|
return new VcnGatewayConnection(
|
||||||
vcnContext,
|
vcnContext,
|
||||||
subscriptionGroup,
|
subscriptionGroup,
|
||||||
snapshot,
|
snapshot,
|
||||||
connectionConfig,
|
connectionConfig,
|
||||||
gatewayStatusCallback);
|
gatewayStatusCallback,
|
||||||
|
isMobileDataEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Builds a new VcnContentResolver instance */
|
||||||
|
public VcnContentResolver newVcnContentResolver(VcnContext vcnContext) {
|
||||||
|
return new VcnContentResolver(vcnContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Proxy Implementation of NetworkAgent, used for testing. */
|
||||||
|
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||||
|
public static class VcnContentResolver {
|
||||||
|
private final ContentResolver mImpl;
|
||||||
|
|
||||||
|
public VcnContentResolver(VcnContext vcnContext) {
|
||||||
|
mImpl = vcnContext.getContext().getContentResolver();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Registers the content observer */
|
||||||
|
public void registerContentObserver(
|
||||||
|
@NonNull Uri uri, boolean notifyForDescendants, @NonNull ContentObserver observer) {
|
||||||
|
mImpl.registerContentObserver(uri, notifyForDescendants, observer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
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_NOT_CONGESTED;
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
|
||||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
|
||||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
|
||||||
@@ -517,6 +519,7 @@ public class VcnGatewayConnection extends StateMachine {
|
|||||||
@NonNull private final VcnGatewayStatusCallback mGatewayStatusCallback;
|
@NonNull private final VcnGatewayStatusCallback mGatewayStatusCallback;
|
||||||
@NonNull private final Dependencies mDeps;
|
@NonNull private final Dependencies mDeps;
|
||||||
@NonNull private final VcnUnderlyingNetworkTrackerCallback mUnderlyingNetworkTrackerCallback;
|
@NonNull private final VcnUnderlyingNetworkTrackerCallback mUnderlyingNetworkTrackerCallback;
|
||||||
|
private final boolean mIsMobileDataEnabled;
|
||||||
|
|
||||||
@NonNull private final IpSecManager mIpSecManager;
|
@NonNull private final IpSecManager mIpSecManager;
|
||||||
|
|
||||||
@@ -626,13 +629,15 @@ public class VcnGatewayConnection extends StateMachine {
|
|||||||
@NonNull ParcelUuid subscriptionGroup,
|
@NonNull ParcelUuid subscriptionGroup,
|
||||||
@NonNull TelephonySubscriptionSnapshot snapshot,
|
@NonNull TelephonySubscriptionSnapshot snapshot,
|
||||||
@NonNull VcnGatewayConnectionConfig connectionConfig,
|
@NonNull VcnGatewayConnectionConfig connectionConfig,
|
||||||
@NonNull VcnGatewayStatusCallback gatewayStatusCallback) {
|
@NonNull VcnGatewayStatusCallback gatewayStatusCallback,
|
||||||
|
boolean isMobileDataEnabled) {
|
||||||
this(
|
this(
|
||||||
vcnContext,
|
vcnContext,
|
||||||
subscriptionGroup,
|
subscriptionGroup,
|
||||||
snapshot,
|
snapshot,
|
||||||
connectionConfig,
|
connectionConfig,
|
||||||
gatewayStatusCallback,
|
gatewayStatusCallback,
|
||||||
|
isMobileDataEnabled,
|
||||||
new Dependencies());
|
new Dependencies());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -643,6 +648,7 @@ public class VcnGatewayConnection extends StateMachine {
|
|||||||
@NonNull TelephonySubscriptionSnapshot snapshot,
|
@NonNull TelephonySubscriptionSnapshot snapshot,
|
||||||
@NonNull VcnGatewayConnectionConfig connectionConfig,
|
@NonNull VcnGatewayConnectionConfig connectionConfig,
|
||||||
@NonNull VcnGatewayStatusCallback gatewayStatusCallback,
|
@NonNull VcnGatewayStatusCallback gatewayStatusCallback,
|
||||||
|
boolean isMobileDataEnabled,
|
||||||
@NonNull Dependencies deps) {
|
@NonNull Dependencies deps) {
|
||||||
super(TAG, Objects.requireNonNull(vcnContext, "Missing vcnContext").getLooper());
|
super(TAG, Objects.requireNonNull(vcnContext, "Missing vcnContext").getLooper());
|
||||||
mVcnContext = vcnContext;
|
mVcnContext = vcnContext;
|
||||||
@@ -650,6 +656,7 @@ public class VcnGatewayConnection extends StateMachine {
|
|||||||
mConnectionConfig = Objects.requireNonNull(connectionConfig, "Missing connectionConfig");
|
mConnectionConfig = Objects.requireNonNull(connectionConfig, "Missing connectionConfig");
|
||||||
mGatewayStatusCallback =
|
mGatewayStatusCallback =
|
||||||
Objects.requireNonNull(gatewayStatusCallback, "Missing gatewayStatusCallback");
|
Objects.requireNonNull(gatewayStatusCallback, "Missing gatewayStatusCallback");
|
||||||
|
mIsMobileDataEnabled = isMobileDataEnabled;
|
||||||
mDeps = Objects.requireNonNull(deps, "Missing deps");
|
mDeps = Objects.requireNonNull(deps, "Missing deps");
|
||||||
|
|
||||||
mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot");
|
mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot");
|
||||||
@@ -1502,7 +1509,7 @@ public class VcnGatewayConnection extends StateMachine {
|
|||||||
@NonNull VcnNetworkAgent agent,
|
@NonNull VcnNetworkAgent agent,
|
||||||
@NonNull VcnChildSessionConfiguration childConfig) {
|
@NonNull VcnChildSessionConfiguration childConfig) {
|
||||||
final NetworkCapabilities caps =
|
final NetworkCapabilities caps =
|
||||||
buildNetworkCapabilities(mConnectionConfig, mUnderlying);
|
buildNetworkCapabilities(mConnectionConfig, mUnderlying, mIsMobileDataEnabled);
|
||||||
final LinkProperties lp =
|
final LinkProperties lp =
|
||||||
buildConnectedLinkProperties(
|
buildConnectedLinkProperties(
|
||||||
mConnectionConfig, tunnelIface, childConfig, mUnderlying);
|
mConnectionConfig, tunnelIface, childConfig, mUnderlying);
|
||||||
@@ -1515,7 +1522,7 @@ public class VcnGatewayConnection extends StateMachine {
|
|||||||
@NonNull IpSecTunnelInterface tunnelIface,
|
@NonNull IpSecTunnelInterface tunnelIface,
|
||||||
@NonNull VcnChildSessionConfiguration childConfig) {
|
@NonNull VcnChildSessionConfiguration childConfig) {
|
||||||
final NetworkCapabilities caps =
|
final NetworkCapabilities caps =
|
||||||
buildNetworkCapabilities(mConnectionConfig, mUnderlying);
|
buildNetworkCapabilities(mConnectionConfig, mUnderlying, mIsMobileDataEnabled);
|
||||||
final LinkProperties lp =
|
final LinkProperties lp =
|
||||||
buildConnectedLinkProperties(
|
buildConnectedLinkProperties(
|
||||||
mConnectionConfig, tunnelIface, childConfig, mUnderlying);
|
mConnectionConfig, tunnelIface, childConfig, mUnderlying);
|
||||||
@@ -1843,7 +1850,8 @@ public class VcnGatewayConnection extends StateMachine {
|
|||||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||||
static NetworkCapabilities buildNetworkCapabilities(
|
static NetworkCapabilities buildNetworkCapabilities(
|
||||||
@NonNull VcnGatewayConnectionConfig gatewayConnectionConfig,
|
@NonNull VcnGatewayConnectionConfig gatewayConnectionConfig,
|
||||||
@Nullable UnderlyingNetworkRecord underlying) {
|
@Nullable UnderlyingNetworkRecord underlying,
|
||||||
|
boolean isMobileDataEnabled) {
|
||||||
final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder();
|
final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder();
|
||||||
|
|
||||||
builder.addTransportType(TRANSPORT_CELLULAR);
|
builder.addTransportType(TRANSPORT_CELLULAR);
|
||||||
@@ -1853,6 +1861,12 @@ public class VcnGatewayConnection extends StateMachine {
|
|||||||
|
|
||||||
// Add exposed capabilities
|
// Add exposed capabilities
|
||||||
for (int cap : gatewayConnectionConfig.getAllExposedCapabilities()) {
|
for (int cap : gatewayConnectionConfig.getAllExposedCapabilities()) {
|
||||||
|
// Skip adding INTERNET or DUN if mobile data is disabled.
|
||||||
|
if (!isMobileDataEnabled
|
||||||
|
&& (cap == NET_CAPABILITY_INTERNET || cap == NET_CAPABILITY_DUN)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
builder.addCapability(cap);
|
builder.addCapability(cap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect
|
|||||||
TEST_SUBSCRIPTION_SNAPSHOT,
|
TEST_SUBSCRIPTION_SNAPSHOT,
|
||||||
mConfig,
|
mConfig,
|
||||||
mGatewayStatusCallback,
|
mGatewayStatusCallback,
|
||||||
|
true /* isMobileDataEnabled */,
|
||||||
mDeps);
|
mDeps);
|
||||||
|
|
||||||
vgc.setIsQuitting(true);
|
vgc.setIsQuitting(true);
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
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_NOT_METERED;
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
|
||||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
|
||||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
|
||||||
@@ -89,7 +91,8 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase {
|
|||||||
doReturn(mWifiInfo).when(mWifiInfo).makeCopy(anyLong());
|
doReturn(mWifiInfo).when(mWifiInfo).makeCopy(anyLong());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void verifyBuildNetworkCapabilitiesCommon(int transportType) {
|
private void verifyBuildNetworkCapabilitiesCommon(
|
||||||
|
int transportType, boolean isMobileDataEnabled) {
|
||||||
final NetworkCapabilities.Builder capBuilder = new NetworkCapabilities.Builder();
|
final NetworkCapabilities.Builder capBuilder = new NetworkCapabilities.Builder();
|
||||||
capBuilder.addTransportType(transportType);
|
capBuilder.addTransportType(transportType);
|
||||||
capBuilder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
|
capBuilder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
|
||||||
@@ -109,10 +112,22 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase {
|
|||||||
capBuilder.build(), new LinkProperties(), false);
|
capBuilder.build(), new LinkProperties(), false);
|
||||||
final NetworkCapabilities vcnCaps =
|
final NetworkCapabilities vcnCaps =
|
||||||
VcnGatewayConnection.buildNetworkCapabilities(
|
VcnGatewayConnection.buildNetworkCapabilities(
|
||||||
VcnGatewayConnectionConfigTest.buildTestConfig(), record);
|
VcnGatewayConnectionConfigTest.buildTestConfig(),
|
||||||
|
record,
|
||||||
|
isMobileDataEnabled);
|
||||||
|
|
||||||
assertTrue(vcnCaps.hasTransport(TRANSPORT_CELLULAR));
|
assertTrue(vcnCaps.hasTransport(TRANSPORT_CELLULAR));
|
||||||
assertTrue(vcnCaps.hasCapability(NET_CAPABILITY_NOT_METERED));
|
assertTrue(vcnCaps.hasCapability(NET_CAPABILITY_NOT_METERED));
|
||||||
assertTrue(vcnCaps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
|
assertTrue(vcnCaps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
|
||||||
|
|
||||||
|
for (int cap : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) {
|
||||||
|
if (cap == NET_CAPABILITY_INTERNET || cap == NET_CAPABILITY_DUN) {
|
||||||
|
assertEquals(isMobileDataEnabled, vcnCaps.hasCapability(cap));
|
||||||
|
} else {
|
||||||
|
assertTrue(vcnCaps.hasCapability(cap));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
assertArrayEquals(new int[] {TEST_UID}, vcnCaps.getAdministratorUids());
|
assertArrayEquals(new int[] {TEST_UID}, vcnCaps.getAdministratorUids());
|
||||||
assertTrue(vcnCaps.getTransportInfo() instanceof VcnTransportInfo);
|
assertTrue(vcnCaps.getTransportInfo() instanceof VcnTransportInfo);
|
||||||
|
|
||||||
@@ -126,12 +141,17 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBuildNetworkCapabilitiesUnderlyingWifi() throws Exception {
|
public void testBuildNetworkCapabilitiesUnderlyingWifi() throws Exception {
|
||||||
verifyBuildNetworkCapabilitiesCommon(TRANSPORT_WIFI);
|
verifyBuildNetworkCapabilitiesCommon(TRANSPORT_WIFI, true /* isMobileDataEnabled */);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBuildNetworkCapabilitiesUnderlyingCell() throws Exception {
|
public void testBuildNetworkCapabilitiesUnderlyingCell() throws Exception {
|
||||||
verifyBuildNetworkCapabilitiesCommon(TRANSPORT_CELLULAR);
|
verifyBuildNetworkCapabilitiesCommon(TRANSPORT_CELLULAR, true /* isMobileDataEnabled */);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuildNetworkCapabilitiesMobileDataDisabled() throws Exception {
|
||||||
|
verifyBuildNetworkCapabilitiesCommon(TRANSPORT_CELLULAR, false /* isMobileDataEnabled */);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -202,6 +202,7 @@ public class VcnGatewayConnectionTestBase {
|
|||||||
TEST_SUBSCRIPTION_SNAPSHOT,
|
TEST_SUBSCRIPTION_SNAPSHOT,
|
||||||
mConfig,
|
mConfig,
|
||||||
mGatewayStatusCallback,
|
mGatewayStatusCallback,
|
||||||
|
true /* isMobileDataEnabled */,
|
||||||
mDeps);
|
mDeps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,16 +16,24 @@
|
|||||||
|
|
||||||
package com.android.server.vcn;
|
package com.android.server.vcn;
|
||||||
|
|
||||||
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
|
||||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
|
||||||
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA;
|
||||||
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
|
||||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
|
||||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
|
||||||
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
|
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_ACTIVE;
|
||||||
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
|
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
|
||||||
|
|
||||||
|
import static com.android.server.vcn.Vcn.VcnContentResolver;
|
||||||
|
|
||||||
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.junit.Assert.assertTrue;
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.Matchers.any;
|
||||||
|
import static org.mockito.Matchers.anyBoolean;
|
||||||
|
import static org.mockito.Matchers.anyInt;
|
||||||
import static org.mockito.Matchers.eq;
|
import static org.mockito.Matchers.eq;
|
||||||
import static org.mockito.Mockito.doAnswer;
|
import static org.mockito.Mockito.doAnswer;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
@@ -35,12 +43,16 @@ import static org.mockito.Mockito.times;
|
|||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.database.ContentObserver;
|
||||||
import android.net.NetworkRequest;
|
import android.net.NetworkRequest;
|
||||||
|
import android.net.Uri;
|
||||||
import android.net.vcn.VcnConfig;
|
import android.net.vcn.VcnConfig;
|
||||||
import android.net.vcn.VcnGatewayConnectionConfig;
|
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.provider.Settings;
|
||||||
|
import android.telephony.TelephonyManager;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
|
|
||||||
import com.android.server.VcnManagementService.VcnCallback;
|
import com.android.server.VcnManagementService.VcnCallback;
|
||||||
@@ -53,7 +65,10 @@ import org.junit.Test;
|
|||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@@ -62,14 +77,21 @@ 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 boolean MOBILE_DATA_ENABLED = true;
|
||||||
|
private static final Set<Integer> TEST_SUB_IDS_IN_GROUP =
|
||||||
|
new ArraySet<>(Arrays.asList(1, 2, 3));
|
||||||
private static final int[][] TEST_CAPS =
|
private static final int[][] TEST_CAPS =
|
||||||
new int[][] {
|
new int[][] {
|
||||||
new int[] {NET_CAPABILITY_MMS, NET_CAPABILITY_INTERNET},
|
new int[] {NET_CAPABILITY_IMS, NET_CAPABILITY_INTERNET, NET_CAPABILITY_DUN},
|
||||||
new int[] {NET_CAPABILITY_DUN}
|
new int[] {NET_CAPABILITY_CBS, NET_CAPABILITY_INTERNET},
|
||||||
|
new int[] {NET_CAPABILITY_FOTA, NET_CAPABILITY_DUN},
|
||||||
|
new int[] {NET_CAPABILITY_MMS}
|
||||||
};
|
};
|
||||||
|
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
private VcnContext mVcnContext;
|
private VcnContext mVcnContext;
|
||||||
|
private TelephonyManager mTelephonyManager;
|
||||||
|
private VcnContentResolver mContentResolver;
|
||||||
private TelephonySubscriptionSnapshot mSubscriptionSnapshot;
|
private TelephonySubscriptionSnapshot mSubscriptionSnapshot;
|
||||||
private VcnNetworkProvider mVcnNetworkProvider;
|
private VcnNetworkProvider mVcnNetworkProvider;
|
||||||
private VcnCallback mVcnCallback;
|
private VcnCallback mVcnCallback;
|
||||||
@@ -86,6 +108,9 @@ public class VcnTest {
|
|||||||
public void setUp() {
|
public void setUp() {
|
||||||
mContext = mock(Context.class);
|
mContext = mock(Context.class);
|
||||||
mVcnContext = mock(VcnContext.class);
|
mVcnContext = mock(VcnContext.class);
|
||||||
|
mTelephonyManager =
|
||||||
|
setupAndGetTelephonyManager(MOBILE_DATA_ENABLED /* isMobileDataEnabled */);
|
||||||
|
mContentResolver = mock(VcnContentResolver.class);
|
||||||
mSubscriptionSnapshot = mock(TelephonySubscriptionSnapshot.class);
|
mSubscriptionSnapshot = mock(TelephonySubscriptionSnapshot.class);
|
||||||
mVcnNetworkProvider = mock(VcnNetworkProvider.class);
|
mVcnNetworkProvider = mock(VcnNetworkProvider.class);
|
||||||
mVcnCallback = mock(VcnCallback.class);
|
mVcnCallback = mock(VcnCallback.class);
|
||||||
@@ -97,12 +122,15 @@ public class VcnTest {
|
|||||||
doReturn(mContext).when(mVcnContext).getContext();
|
doReturn(mContext).when(mVcnContext).getContext();
|
||||||
doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper();
|
doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper();
|
||||||
doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider();
|
doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider();
|
||||||
|
doReturn(mContentResolver).when(mDeps).newVcnContentResolver(eq(mVcnContext));
|
||||||
|
|
||||||
// Setup VcnGatewayConnection instance generation
|
// Setup VcnGatewayConnection instance generation
|
||||||
doAnswer((invocation) -> {
|
doAnswer((invocation) -> {
|
||||||
// Mock-within a doAnswer is safe, because it doesn't actually run nested.
|
// Mock-within a doAnswer is safe, because it doesn't actually run nested.
|
||||||
return mock(VcnGatewayConnection.class);
|
return mock(VcnGatewayConnection.class);
|
||||||
}).when(mDeps).newVcnGatewayConnection(any(), any(), any(), any(), any());
|
}).when(mDeps).newVcnGatewayConnection(any(), any(), any(), any(), any(), anyBoolean());
|
||||||
|
|
||||||
|
doReturn(TEST_SUB_IDS_IN_GROUP).when(mSubscriptionSnapshot).getAllSubIdsInGroup(any());
|
||||||
|
|
||||||
mGatewayStatusCallbackCaptor = ArgumentCaptor.forClass(VcnGatewayStatusCallback.class);
|
mGatewayStatusCallbackCaptor = ArgumentCaptor.forClass(VcnGatewayStatusCallback.class);
|
||||||
|
|
||||||
@@ -123,6 +151,16 @@ public class VcnTest {
|
|||||||
mDeps);
|
mDeps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private TelephonyManager setupAndGetTelephonyManager(boolean isMobileDataEnabled) {
|
||||||
|
final TelephonyManager telephonyManager = mock(TelephonyManager.class);
|
||||||
|
VcnTestUtils.setupSystemService(
|
||||||
|
mContext, telephonyManager, Context.TELEPHONY_SERVICE, TelephonyManager.class);
|
||||||
|
doReturn(telephonyManager).when(telephonyManager).createForSubscriptionId(anyInt());
|
||||||
|
doReturn(isMobileDataEnabled).when(telephonyManager).isDataEnabled();
|
||||||
|
|
||||||
|
return telephonyManager;
|
||||||
|
}
|
||||||
|
|
||||||
private NetworkRequestListener verifyAndGetRequestListener() {
|
private NetworkRequestListener verifyAndGetRequestListener() {
|
||||||
ArgumentCaptor<NetworkRequestListener> mNetworkRequestListenerCaptor =
|
ArgumentCaptor<NetworkRequestListener> mNetworkRequestListenerCaptor =
|
||||||
ArgumentCaptor.forClass(NetworkRequestListener.class);
|
ArgumentCaptor.forClass(NetworkRequestListener.class);
|
||||||
@@ -163,6 +201,39 @@ public class VcnTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testContentObserverRegistered() {
|
||||||
|
// Validate state from setUp()
|
||||||
|
final Uri uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA);
|
||||||
|
verify(mContentResolver)
|
||||||
|
.registerContentObserver(eq(uri), eq(true), any(ContentObserver.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMobileDataStateCheckedOnInitialization_enabled() {
|
||||||
|
// Validate state from setUp()
|
||||||
|
assertTrue(mVcn.isMobileDataEnabled());
|
||||||
|
verify(mTelephonyManager).isDataEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMobileDataStateCheckedOnInitialization_disabled() {
|
||||||
|
// Build and setup new telephonyManager to ensure method call count is reset.
|
||||||
|
final TelephonyManager telephonyManager =
|
||||||
|
setupAndGetTelephonyManager(false /* isMobileDataEnabled */);
|
||||||
|
final Vcn vcn =
|
||||||
|
new Vcn(
|
||||||
|
mVcnContext,
|
||||||
|
TEST_SUB_GROUP,
|
||||||
|
mConfig,
|
||||||
|
mSubscriptionSnapshot,
|
||||||
|
mVcnCallback,
|
||||||
|
mDeps);
|
||||||
|
|
||||||
|
assertFalse(vcn.isMobileDataEnabled());
|
||||||
|
verify(mTelephonyManager).isDataEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSubscriptionSnapshotUpdatesVcnGatewayConnections() {
|
public void testSubscriptionSnapshotUpdatesVcnGatewayConnections() {
|
||||||
verifyUpdateSubscriptionSnapshotNotifiesGatewayConnections(VCN_STATUS_CODE_ACTIVE);
|
verifyUpdateSubscriptionSnapshotNotifiesGatewayConnections(VCN_STATUS_CODE_ACTIVE);
|
||||||
@@ -193,7 +264,8 @@ public class VcnTest {
|
|||||||
eq(TEST_SUB_GROUP),
|
eq(TEST_SUB_GROUP),
|
||||||
eq(mSubscriptionSnapshot),
|
eq(mSubscriptionSnapshot),
|
||||||
any(),
|
any(),
|
||||||
mGatewayStatusCallbackCaptor.capture());
|
mGatewayStatusCallbackCaptor.capture(),
|
||||||
|
eq(MOBILE_DATA_ENABLED));
|
||||||
|
|
||||||
return gatewayConnections;
|
return gatewayConnections;
|
||||||
}
|
}
|
||||||
@@ -256,20 +328,21 @@ public class VcnTest {
|
|||||||
mTestLooper.dispatchAll();
|
mTestLooper.dispatchAll();
|
||||||
|
|
||||||
// Verify that the VCN requests the networkRequests be resent
|
// Verify that the VCN requests the networkRequests be resent
|
||||||
assertEquals(1, mVcn.getVcnGatewayConnections().size());
|
assertEquals(gatewayConnections.size() - 1, mVcn.getVcnGatewayConnections().size());
|
||||||
verify(mVcnNetworkProvider).resendAllRequests(requestListener);
|
verify(mVcnNetworkProvider).resendAllRequests(requestListener);
|
||||||
|
|
||||||
// Verify that the VcnGatewayConnection is restarted if a request exists for it
|
// Verify that the VcnGatewayConnection is restarted if a request exists for it
|
||||||
triggerVcnRequestListeners(requestListener);
|
triggerVcnRequestListeners(requestListener);
|
||||||
mTestLooper.dispatchAll();
|
mTestLooper.dispatchAll();
|
||||||
assertEquals(2, mVcn.getVcnGatewayConnections().size());
|
assertEquals(gatewayConnections.size(), mVcn.getVcnGatewayConnections().size());
|
||||||
verify(mDeps, times(gatewayConnections.size() + 1))
|
verify(mDeps, times(gatewayConnections.size() + 1))
|
||||||
.newVcnGatewayConnection(
|
.newVcnGatewayConnection(
|
||||||
eq(mVcnContext),
|
eq(mVcnContext),
|
||||||
eq(TEST_SUB_GROUP),
|
eq(TEST_SUB_GROUP),
|
||||||
eq(mSubscriptionSnapshot),
|
eq(mSubscriptionSnapshot),
|
||||||
any(),
|
any(),
|
||||||
mGatewayStatusCallbackCaptor.capture());
|
mGatewayStatusCallbackCaptor.capture(),
|
||||||
|
anyBoolean());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -286,7 +359,7 @@ public class VcnTest {
|
|||||||
public void testUpdateConfigReevaluatesGatewayConnections() {
|
public void testUpdateConfigReevaluatesGatewayConnections() {
|
||||||
final NetworkRequestListener requestListener = verifyAndGetRequestListener();
|
final NetworkRequestListener requestListener = verifyAndGetRequestListener();
|
||||||
startGatewaysAndGetGatewayConnections(requestListener);
|
startGatewaysAndGetGatewayConnections(requestListener);
|
||||||
assertEquals(2, mVcn.getVcnGatewayConnectionConfigMap().size());
|
assertEquals(TEST_CAPS.length, mVcn.getVcnGatewayConnectionConfigMap().size());
|
||||||
|
|
||||||
// Create VcnConfig with only one VcnGatewayConnectionConfig so a gateway connection is torn
|
// Create VcnConfig with only one VcnGatewayConnectionConfig so a gateway connection is torn
|
||||||
// down. Reuse existing VcnGatewayConnectionConfig so that the gateway connection name
|
// down. Reuse existing VcnGatewayConnectionConfig so that the gateway connection name
|
||||||
@@ -309,4 +382,57 @@ public class VcnTest {
|
|||||||
verify(removedGatewayConnection).teardownAsynchronously();
|
verify(removedGatewayConnection).teardownAsynchronously();
|
||||||
verify(mVcnNetworkProvider).resendAllRequests(requestListener);
|
verify(mVcnNetworkProvider).resendAllRequests(requestListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void verifyMobileDataToggled(boolean startingToggleState, boolean endingToggleState) {
|
||||||
|
final ArgumentCaptor<ContentObserver> captor =
|
||||||
|
ArgumentCaptor.forClass(ContentObserver.class);
|
||||||
|
verify(mContentResolver).registerContentObserver(any(), anyBoolean(), captor.capture());
|
||||||
|
final ContentObserver contentObserver = captor.getValue();
|
||||||
|
|
||||||
|
// Start VcnGatewayConnections
|
||||||
|
mVcn.setMobileDataEnabled(startingToggleState);
|
||||||
|
triggerVcnRequestListeners(verifyAndGetRequestListener());
|
||||||
|
final Map<VcnGatewayConnectionConfig, VcnGatewayConnection> gateways =
|
||||||
|
mVcn.getVcnGatewayConnectionConfigMap();
|
||||||
|
|
||||||
|
// Trigger data toggle change.
|
||||||
|
doReturn(endingToggleState).when(mTelephonyManager).isDataEnabled();
|
||||||
|
contentObserver.onChange(false /* selfChange, ignored */);
|
||||||
|
mTestLooper.dispatchAll();
|
||||||
|
|
||||||
|
// Verify that data toggle changes restart ONLY INTERNET or DUN networks, and only if the
|
||||||
|
// toggle state changed.
|
||||||
|
for (Entry<VcnGatewayConnectionConfig, VcnGatewayConnection> entry : gateways.entrySet()) {
|
||||||
|
final Set<Integer> exposedCaps = entry.getKey().getAllExposedCapabilities();
|
||||||
|
if (startingToggleState != endingToggleState
|
||||||
|
&& (exposedCaps.contains(NET_CAPABILITY_INTERNET)
|
||||||
|
|| exposedCaps.contains(NET_CAPABILITY_DUN))) {
|
||||||
|
verify(entry.getValue()).teardownAsynchronously();
|
||||||
|
} else {
|
||||||
|
verify(entry.getValue(), never()).teardownAsynchronously();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(endingToggleState, mVcn.isMobileDataEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMobileDataEnabled() {
|
||||||
|
verifyMobileDataToggled(false /* startingToggleState */, true /* endingToggleState */);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMobileDataDisabled() {
|
||||||
|
verifyMobileDataToggled(true /* startingToggleState */, false /* endingToggleState */);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMobileDataObserverFiredWithoutChanges_dataEnabled() {
|
||||||
|
verifyMobileDataToggled(false /* startingToggleState */, false /* endingToggleState */);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMobileDataObserverFiredWithoutChanges_dataDisabled() {
|
||||||
|
verifyMobileDataToggled(true /* startingToggleState */, true /* endingToggleState */);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user