Disable INTERNET/DUN when mobile data toggled off am: 061c84ba27 am: 725dcd8103
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1670525 Change-Id: Icd6ba18d98677986f8a939937b7c35532fceb51f
This commit is contained in:
@@ -16,6 +16,8 @@
|
||||
|
||||
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.TRANSPORT_CELLULAR;
|
||||
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.Nullable;
|
||||
import android.content.ContentResolver;
|
||||
import android.database.ContentObserver;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.NetworkRequest;
|
||||
import android.net.Uri;
|
||||
import android.net.vcn.VcnConfig;
|
||||
import android.net.vcn.VcnGatewayConnectionConfig;
|
||||
import android.net.vcn.VcnManager.VcnErrorCode;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.os.ParcelUuid;
|
||||
import android.provider.Settings;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Slog;
|
||||
|
||||
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.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
@@ -61,6 +71,9 @@ import java.util.Set;
|
||||
public class Vcn extends Handler {
|
||||
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_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;
|
||||
|
||||
/**
|
||||
* 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. */
|
||||
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 VcnNetworkRequestListener mRequestListener;
|
||||
@NonNull private final VcnCallback mVcnCallback;
|
||||
@NonNull private final VcnContentResolver mContentResolver;
|
||||
@NonNull private final ContentObserver mMobileDataSettingsObserver;
|
||||
|
||||
/**
|
||||
* 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
|
||||
private volatile int mCurrentStatus = VCN_STATUS_CODE_ACTIVE;
|
||||
|
||||
private boolean mIsMobileDataEnabled = false;
|
||||
|
||||
public Vcn(
|
||||
@NonNull VcnContext vcnContext,
|
||||
@NonNull ParcelUuid subscriptionGroup,
|
||||
@@ -177,10 +203,19 @@ public class Vcn extends Handler {
|
||||
mVcnCallback = Objects.requireNonNull(vcnCallback, "Missing vcnCallback");
|
||||
mDeps = Objects.requireNonNull(deps, "Missing deps");
|
||||
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");
|
||||
mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot");
|
||||
|
||||
// Update mIsMobileDataEnabled before starting handling of NetworkRequests.
|
||||
mIsMobileDataEnabled = getMobileDataStatus();
|
||||
|
||||
// Register to receive cached and future NetworkRequests
|
||||
mVcnContext.getVcnNetworkProvider().registerListener(mRequestListener);
|
||||
}
|
||||
@@ -260,6 +295,9 @@ public class Vcn extends Handler {
|
||||
case MSG_EVENT_SAFE_MODE_STATE_CHANGED:
|
||||
handleSafeModeStatusChanged();
|
||||
break;
|
||||
case MSG_EVENT_MOBILE_DATA_TOGGLED:
|
||||
handleMobileDataToggled();
|
||||
break;
|
||||
case MSG_CMD_TEARDOWN:
|
||||
handleTeardown();
|
||||
break;
|
||||
@@ -366,18 +404,37 @@ public class Vcn extends Handler {
|
||||
if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
|
||||
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 =
|
||||
mDeps.newVcnGatewayConnection(
|
||||
mVcnContext,
|
||||
mSubscriptionGroup,
|
||||
mLastSnapshot,
|
||||
gatewayConnectionConfig,
|
||||
new VcnGatewayStatusCallbackImpl(gatewayConnectionConfig));
|
||||
new VcnGatewayStatusCallbackImpl(gatewayConnectionConfig),
|
||||
mIsMobileDataEnabled);
|
||||
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) {
|
||||
Slog.v(getLogTag(), "VcnGatewayConnection quit: " + 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(
|
||||
@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()) {
|
||||
for (int cap : getExposedCapabilitiesForMobileDataState(config)) {
|
||||
builder.addCapability(cap);
|
||||
}
|
||||
|
||||
@@ -432,6 +532,16 @@ public class Vcn extends Handler {
|
||||
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 */
|
||||
// Package visibility for use in VcnGatewayConnection
|
||||
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 */
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
public static class Dependencies {
|
||||
@@ -494,13 +615,36 @@ public class Vcn extends Handler {
|
||||
ParcelUuid subscriptionGroup,
|
||||
TelephonySubscriptionSnapshot snapshot,
|
||||
VcnGatewayConnectionConfig connectionConfig,
|
||||
VcnGatewayStatusCallback gatewayStatusCallback) {
|
||||
VcnGatewayStatusCallback gatewayStatusCallback,
|
||||
boolean isMobileDataEnabled) {
|
||||
return new VcnGatewayConnection(
|
||||
vcnContext,
|
||||
subscriptionGroup,
|
||||
snapshot,
|
||||
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;
|
||||
|
||||
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_METERED;
|
||||
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 Dependencies mDeps;
|
||||
@NonNull private final VcnUnderlyingNetworkTrackerCallback mUnderlyingNetworkTrackerCallback;
|
||||
private final boolean mIsMobileDataEnabled;
|
||||
|
||||
@NonNull private final IpSecManager mIpSecManager;
|
||||
|
||||
@@ -626,13 +629,15 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
@NonNull ParcelUuid subscriptionGroup,
|
||||
@NonNull TelephonySubscriptionSnapshot snapshot,
|
||||
@NonNull VcnGatewayConnectionConfig connectionConfig,
|
||||
@NonNull VcnGatewayStatusCallback gatewayStatusCallback) {
|
||||
@NonNull VcnGatewayStatusCallback gatewayStatusCallback,
|
||||
boolean isMobileDataEnabled) {
|
||||
this(
|
||||
vcnContext,
|
||||
subscriptionGroup,
|
||||
snapshot,
|
||||
connectionConfig,
|
||||
gatewayStatusCallback,
|
||||
isMobileDataEnabled,
|
||||
new Dependencies());
|
||||
}
|
||||
|
||||
@@ -643,6 +648,7 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
@NonNull TelephonySubscriptionSnapshot snapshot,
|
||||
@NonNull VcnGatewayConnectionConfig connectionConfig,
|
||||
@NonNull VcnGatewayStatusCallback gatewayStatusCallback,
|
||||
boolean isMobileDataEnabled,
|
||||
@NonNull Dependencies deps) {
|
||||
super(TAG, Objects.requireNonNull(vcnContext, "Missing vcnContext").getLooper());
|
||||
mVcnContext = vcnContext;
|
||||
@@ -650,6 +656,7 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
mConnectionConfig = Objects.requireNonNull(connectionConfig, "Missing connectionConfig");
|
||||
mGatewayStatusCallback =
|
||||
Objects.requireNonNull(gatewayStatusCallback, "Missing gatewayStatusCallback");
|
||||
mIsMobileDataEnabled = isMobileDataEnabled;
|
||||
mDeps = Objects.requireNonNull(deps, "Missing deps");
|
||||
|
||||
mLastSnapshot = Objects.requireNonNull(snapshot, "Missing snapshot");
|
||||
@@ -1502,7 +1509,7 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
@NonNull VcnNetworkAgent agent,
|
||||
@NonNull VcnChildSessionConfiguration childConfig) {
|
||||
final NetworkCapabilities caps =
|
||||
buildNetworkCapabilities(mConnectionConfig, mUnderlying);
|
||||
buildNetworkCapabilities(mConnectionConfig, mUnderlying, mIsMobileDataEnabled);
|
||||
final LinkProperties lp =
|
||||
buildConnectedLinkProperties(
|
||||
mConnectionConfig, tunnelIface, childConfig, mUnderlying);
|
||||
@@ -1515,7 +1522,7 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
@NonNull IpSecTunnelInterface tunnelIface,
|
||||
@NonNull VcnChildSessionConfiguration childConfig) {
|
||||
final NetworkCapabilities caps =
|
||||
buildNetworkCapabilities(mConnectionConfig, mUnderlying);
|
||||
buildNetworkCapabilities(mConnectionConfig, mUnderlying, mIsMobileDataEnabled);
|
||||
final LinkProperties lp =
|
||||
buildConnectedLinkProperties(
|
||||
mConnectionConfig, tunnelIface, childConfig, mUnderlying);
|
||||
@@ -1843,7 +1850,8 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
@VisibleForTesting(visibility = Visibility.PRIVATE)
|
||||
static NetworkCapabilities buildNetworkCapabilities(
|
||||
@NonNull VcnGatewayConnectionConfig gatewayConnectionConfig,
|
||||
@Nullable UnderlyingNetworkRecord underlying) {
|
||||
@Nullable UnderlyingNetworkRecord underlying,
|
||||
boolean isMobileDataEnabled) {
|
||||
final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder();
|
||||
|
||||
builder.addTransportType(TRANSPORT_CELLULAR);
|
||||
@@ -1853,6 +1861,12 @@ public class VcnGatewayConnection extends StateMachine {
|
||||
|
||||
// Add exposed capabilities
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect
|
||||
TEST_SUBSCRIPTION_SNAPSHOT,
|
||||
mConfig,
|
||||
mGatewayStatusCallback,
|
||||
true /* isMobileDataEnabled */,
|
||||
mDeps);
|
||||
|
||||
vgc.setIsQuitting(true);
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
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_ROAMING;
|
||||
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());
|
||||
}
|
||||
|
||||
private void verifyBuildNetworkCapabilitiesCommon(int transportType) {
|
||||
private void verifyBuildNetworkCapabilitiesCommon(
|
||||
int transportType, boolean isMobileDataEnabled) {
|
||||
final NetworkCapabilities.Builder capBuilder = new NetworkCapabilities.Builder();
|
||||
capBuilder.addTransportType(transportType);
|
||||
capBuilder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
|
||||
@@ -109,10 +112,22 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase {
|
||||
capBuilder.build(), new LinkProperties(), false);
|
||||
final NetworkCapabilities vcnCaps =
|
||||
VcnGatewayConnection.buildNetworkCapabilities(
|
||||
VcnGatewayConnectionConfigTest.buildTestConfig(), record);
|
||||
VcnGatewayConnectionConfigTest.buildTestConfig(),
|
||||
record,
|
||||
isMobileDataEnabled);
|
||||
|
||||
assertTrue(vcnCaps.hasTransport(TRANSPORT_CELLULAR));
|
||||
assertTrue(vcnCaps.hasCapability(NET_CAPABILITY_NOT_METERED));
|
||||
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());
|
||||
assertTrue(vcnCaps.getTransportInfo() instanceof VcnTransportInfo);
|
||||
|
||||
@@ -126,12 +141,17 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase {
|
||||
|
||||
@Test
|
||||
public void testBuildNetworkCapabilitiesUnderlyingWifi() throws Exception {
|
||||
verifyBuildNetworkCapabilitiesCommon(TRANSPORT_WIFI);
|
||||
verifyBuildNetworkCapabilitiesCommon(TRANSPORT_WIFI, true /* isMobileDataEnabled */);
|
||||
}
|
||||
|
||||
@Test
|
||||
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
|
||||
|
||||
@@ -202,6 +202,7 @@ public class VcnGatewayConnectionTestBase {
|
||||
TEST_SUBSCRIPTION_SNAPSHOT,
|
||||
mConfig,
|
||||
mGatewayStatusCallback,
|
||||
true /* isMobileDataEnabled */,
|
||||
mDeps);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,16 +16,24 @@
|
||||
|
||||
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_FOTA;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
|
||||
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_SAFE_MODE;
|
||||
|
||||
import static com.android.server.vcn.Vcn.VcnContentResolver;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyBoolean;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
@@ -35,12 +43,16 @@ import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.ContentObserver;
|
||||
import android.net.NetworkRequest;
|
||||
import android.net.Uri;
|
||||
import android.net.vcn.VcnConfig;
|
||||
import android.net.vcn.VcnGatewayConnectionConfig;
|
||||
import android.net.vcn.VcnGatewayConnectionConfigTest;
|
||||
import android.os.ParcelUuid;
|
||||
import android.os.test.TestLooper;
|
||||
import android.provider.Settings;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.ArraySet;
|
||||
|
||||
import com.android.server.VcnManagementService.VcnCallback;
|
||||
@@ -53,7 +65,10 @@ import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
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 int NETWORK_SCORE = 0;
|
||||
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 =
|
||||
new int[][] {
|
||||
new int[] {NET_CAPABILITY_MMS, NET_CAPABILITY_INTERNET},
|
||||
new int[] {NET_CAPABILITY_DUN}
|
||||
new int[] {NET_CAPABILITY_IMS, NET_CAPABILITY_INTERNET, 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 VcnContext mVcnContext;
|
||||
private TelephonyManager mTelephonyManager;
|
||||
private VcnContentResolver mContentResolver;
|
||||
private TelephonySubscriptionSnapshot mSubscriptionSnapshot;
|
||||
private VcnNetworkProvider mVcnNetworkProvider;
|
||||
private VcnCallback mVcnCallback;
|
||||
@@ -86,6 +108,9 @@ public class VcnTest {
|
||||
public void setUp() {
|
||||
mContext = mock(Context.class);
|
||||
mVcnContext = mock(VcnContext.class);
|
||||
mTelephonyManager =
|
||||
setupAndGetTelephonyManager(MOBILE_DATA_ENABLED /* isMobileDataEnabled */);
|
||||
mContentResolver = mock(VcnContentResolver.class);
|
||||
mSubscriptionSnapshot = mock(TelephonySubscriptionSnapshot.class);
|
||||
mVcnNetworkProvider = mock(VcnNetworkProvider.class);
|
||||
mVcnCallback = mock(VcnCallback.class);
|
||||
@@ -97,12 +122,15 @@ public class VcnTest {
|
||||
doReturn(mContext).when(mVcnContext).getContext();
|
||||
doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper();
|
||||
doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider();
|
||||
doReturn(mContentResolver).when(mDeps).newVcnContentResolver(eq(mVcnContext));
|
||||
|
||||
// Setup VcnGatewayConnection instance generation
|
||||
doAnswer((invocation) -> {
|
||||
// Mock-within a doAnswer is safe, because it doesn't actually run nested.
|
||||
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);
|
||||
|
||||
@@ -123,6 +151,16 @@ public class VcnTest {
|
||||
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() {
|
||||
ArgumentCaptor<NetworkRequestListener> mNetworkRequestListenerCaptor =
|
||||
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
|
||||
public void testSubscriptionSnapshotUpdatesVcnGatewayConnections() {
|
||||
verifyUpdateSubscriptionSnapshotNotifiesGatewayConnections(VCN_STATUS_CODE_ACTIVE);
|
||||
@@ -193,7 +264,8 @@ public class VcnTest {
|
||||
eq(TEST_SUB_GROUP),
|
||||
eq(mSubscriptionSnapshot),
|
||||
any(),
|
||||
mGatewayStatusCallbackCaptor.capture());
|
||||
mGatewayStatusCallbackCaptor.capture(),
|
||||
eq(MOBILE_DATA_ENABLED));
|
||||
|
||||
return gatewayConnections;
|
||||
}
|
||||
@@ -256,20 +328,21 @@ public class VcnTest {
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
// 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 that the VcnGatewayConnection is restarted if a request exists for it
|
||||
triggerVcnRequestListeners(requestListener);
|
||||
mTestLooper.dispatchAll();
|
||||
assertEquals(2, mVcn.getVcnGatewayConnections().size());
|
||||
assertEquals(gatewayConnections.size(), mVcn.getVcnGatewayConnections().size());
|
||||
verify(mDeps, times(gatewayConnections.size() + 1))
|
||||
.newVcnGatewayConnection(
|
||||
eq(mVcnContext),
|
||||
eq(TEST_SUB_GROUP),
|
||||
eq(mSubscriptionSnapshot),
|
||||
any(),
|
||||
mGatewayStatusCallbackCaptor.capture());
|
||||
mGatewayStatusCallbackCaptor.capture(),
|
||||
anyBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -286,7 +359,7 @@ public class VcnTest {
|
||||
public void testUpdateConfigReevaluatesGatewayConnections() {
|
||||
final NetworkRequestListener requestListener = verifyAndGetRequestListener();
|
||||
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
|
||||
// down. Reuse existing VcnGatewayConnectionConfig so that the gateway connection name
|
||||
@@ -309,4 +382,57 @@ public class VcnTest {
|
||||
verify(removedGatewayConnection).teardownAsynchronously();
|
||||
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