Merge changes Ib0690243,I0cabce70,I8f13a0d8,I81efeaa4,I488f6208
* changes: Switch to using NetworkScore instead of legacy integer Remove use of network scores, and provider IDs in VcnNetworkProvider Improve dump detail Disable INTERNET/DUN when mobile data toggled off Remove hidden connectivity method access in FrameworksVcnTests
This commit is contained in:
@@ -936,13 +936,31 @@ public class VcnManagementService extends IVcnManagementService.Stub {
|
|||||||
pw.println("VcnManagementService dump:");
|
pw.println("VcnManagementService dump:");
|
||||||
pw.increaseIndent();
|
pw.increaseIndent();
|
||||||
|
|
||||||
|
pw.println("mNetworkProvider:");
|
||||||
|
pw.increaseIndent();
|
||||||
mNetworkProvider.dump(pw);
|
mNetworkProvider.dump(pw);
|
||||||
|
pw.decreaseIndent();
|
||||||
|
pw.println();
|
||||||
|
|
||||||
|
pw.println("mTrackingNetworkCallback:");
|
||||||
|
pw.increaseIndent();
|
||||||
|
mTrackingNetworkCallback.dump(pw);
|
||||||
|
pw.decreaseIndent();
|
||||||
|
pw.println();
|
||||||
|
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
|
pw.println("mLastSnapshot:");
|
||||||
|
pw.increaseIndent();
|
||||||
|
mLastSnapshot.dump(pw);
|
||||||
|
pw.decreaseIndent();
|
||||||
|
pw.println();
|
||||||
|
|
||||||
pw.println("mVcns:");
|
pw.println("mVcns:");
|
||||||
|
pw.increaseIndent();
|
||||||
for (Vcn vcn : mVcns.values()) {
|
for (Vcn vcn : mVcns.values()) {
|
||||||
vcn.dump(pw);
|
vcn.dump(pw);
|
||||||
}
|
}
|
||||||
|
pw.decreaseIndent();
|
||||||
pw.println();
|
pw.println();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1004,6 +1022,24 @@ public class VcnManagementService extends IVcnManagementService.Stub {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Dumps the state of this snapshot for logging and debugging purposes. */
|
||||||
|
public void dump(IndentingPrintWriter pw) {
|
||||||
|
pw.println("TrackingNetworkCallback:");
|
||||||
|
pw.increaseIndent();
|
||||||
|
|
||||||
|
pw.println("mCaps:");
|
||||||
|
pw.increaseIndent();
|
||||||
|
synchronized (mCaps) {
|
||||||
|
for (Entry<Network, NetworkCapabilities> entry : mCaps.entrySet()) {
|
||||||
|
pw.println(entry.getKey() + ": " + entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pw.decreaseIndent();
|
||||||
|
pw.println();
|
||||||
|
|
||||||
|
pw.decreaseIndent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** VcnCallbackImpl for Vcn signals sent up to VcnManagementService. */
|
/** VcnCallbackImpl for Vcn signals sent up to VcnManagementService. */
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import android.util.Slog;
|
|||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.annotations.VisibleForTesting.Visibility;
|
import com.android.internal.annotations.VisibleForTesting.Visibility;
|
||||||
|
import com.android.internal.util.IndentingPrintWriter;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -320,6 +321,17 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver {
|
|||||||
&& mPrivilegedPackages.equals(other.mPrivilegedPackages);
|
&& mPrivilegedPackages.equals(other.mPrivilegedPackages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Dumps the state of this snapshot for logging and debugging purposes. */
|
||||||
|
public void dump(IndentingPrintWriter pw) {
|
||||||
|
pw.println("TelephonySubscriptionSnapshot:");
|
||||||
|
pw.increaseIndent();
|
||||||
|
|
||||||
|
pw.println("mSubIdToGroupMap: " + mSubIdToGroupMap);
|
||||||
|
pw.println("mPrivilegedPackages: " + mPrivilegedPackages);
|
||||||
|
|
||||||
|
pw.decreaseIndent();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "TelephonySubscriptionSnapshot{ "
|
return "TelephonySubscriptionSnapshot{ "
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import android.util.Slog;
|
|||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.annotations.VisibleForTesting.Visibility;
|
import com.android.internal.annotations.VisibleForTesting.Visibility;
|
||||||
|
import com.android.internal.util.IndentingPrintWriter;
|
||||||
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
|
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -396,6 +397,18 @@ public class UnderlyingNetworkTracker {
|
|||||||
return Objects.hash(network, networkCapabilities, linkProperties, isBlocked);
|
return Objects.hash(network, networkCapabilities, linkProperties, isBlocked);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Dumps the state of this record for logging and debugging purposes. */
|
||||||
|
public void dump(IndentingPrintWriter pw) {
|
||||||
|
pw.println("UnderlyingNetworkRecord:");
|
||||||
|
pw.increaseIndent();
|
||||||
|
|
||||||
|
pw.println("mNetwork: " + network);
|
||||||
|
pw.println("mNetworkCapabilities: " + networkCapabilities);
|
||||||
|
pw.println("mLinkProperties: " + linkProperties);
|
||||||
|
|
||||||
|
pw.decreaseIndent();
|
||||||
|
}
|
||||||
|
|
||||||
/** Builder to incrementally construct an UnderlyingNetworkRecord. */
|
/** Builder to incrementally construct an UnderlyingNetworkRecord. */
|
||||||
private static class Builder {
|
private static class Builder {
|
||||||
@NonNull private final Network mNetwork;
|
@NonNull private final Network mNetwork;
|
||||||
|
|||||||
@@ -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,21 @@ 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.NetworkScore;
|
||||||
|
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 +51,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 +72,11 @@ 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 int VCN_LEGACY_SCORE_INT = 52;
|
||||||
|
|
||||||
|
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 +126,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 +143,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 +181,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 +206,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);
|
||||||
}
|
}
|
||||||
@@ -230,10 +268,10 @@ public class Vcn extends Handler {
|
|||||||
|
|
||||||
private class VcnNetworkRequestListener implements VcnNetworkProvider.NetworkRequestListener {
|
private class VcnNetworkRequestListener implements VcnNetworkProvider.NetworkRequestListener {
|
||||||
@Override
|
@Override
|
||||||
public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) {
|
public void onNetworkRequested(@NonNull NetworkRequest request) {
|
||||||
Objects.requireNonNull(request, "Missing request");
|
Objects.requireNonNull(request, "Missing request");
|
||||||
|
|
||||||
sendMessage(obtainMessage(MSG_EVENT_NETWORK_REQUESTED, score, providerId, request));
|
sendMessage(obtainMessage(MSG_EVENT_NETWORK_REQUESTED, request));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,7 +287,7 @@ public class Vcn extends Handler {
|
|||||||
handleConfigUpdated((VcnConfig) msg.obj);
|
handleConfigUpdated((VcnConfig) msg.obj);
|
||||||
break;
|
break;
|
||||||
case MSG_EVENT_NETWORK_REQUESTED:
|
case MSG_EVENT_NETWORK_REQUESTED:
|
||||||
handleNetworkRequested((NetworkRequest) msg.obj, msg.arg1, msg.arg2);
|
handleNetworkRequested((NetworkRequest) msg.obj);
|
||||||
break;
|
break;
|
||||||
case MSG_EVENT_SUBSCRIPTIONS_CHANGED:
|
case MSG_EVENT_SUBSCRIPTIONS_CHANGED:
|
||||||
handleSubscriptionsChanged((TelephonySubscriptionSnapshot) msg.obj);
|
handleSubscriptionsChanged((TelephonySubscriptionSnapshot) msg.obj);
|
||||||
@@ -260,6 +298,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;
|
||||||
@@ -327,25 +368,9 @@ public class Vcn extends Handler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleNetworkRequested(
|
private void handleNetworkRequested(@NonNull NetworkRequest request) {
|
||||||
@NonNull NetworkRequest request, int score, int providerId) {
|
|
||||||
Slog.v(getLogTag(), "Received request " + request);
|
Slog.v(getLogTag(), "Received request " + request);
|
||||||
|
|
||||||
if (score > getNetworkScore()) {
|
|
||||||
if (VDBG) {
|
|
||||||
Slog.v(
|
|
||||||
getLogTag(),
|
|
||||||
"Request already satisfied by higher-scoring ("
|
|
||||||
+ score
|
|
||||||
+ ") network from "
|
|
||||||
+ "provider "
|
|
||||||
+ providerId
|
|
||||||
+ ": "
|
|
||||||
+ request);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If preexisting VcnGatewayConnection(s) satisfy request, return
|
// If preexisting VcnGatewayConnection(s) satisfy request, return
|
||||||
for (VcnGatewayConnectionConfig gatewayConnectionConfig : mVcnGatewayConnections.keySet()) {
|
for (VcnGatewayConnectionConfig gatewayConnectionConfig : mVcnGatewayConnections.keySet()) {
|
||||||
if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
|
if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
|
||||||
@@ -366,18 +391,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 +440,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,12 +519,20 @@ 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 and VcnNetworkProvider
|
||||||
static int getNetworkScore() {
|
static NetworkScore getNetworkScore() {
|
||||||
// TODO: STOPSHIP (b/173549607): Make this use new NetworkSelection, or some magic "max in
|
return new NetworkScore.Builder().setLegacyInt(VCN_LEGACY_SCORE_INT).build();
|
||||||
// subGrp" value
|
|
||||||
return 52;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Callback used for passing status signals from a VcnGatewayConnection to its managing Vcn. */
|
/** Callback used for passing status signals from a VcnGatewayConnection to its managing Vcn. */
|
||||||
@@ -485,6 +580,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 +600,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;
|
||||||
@@ -47,6 +49,7 @@ import android.net.NetworkAgent;
|
|||||||
import android.net.NetworkAgentConfig;
|
import android.net.NetworkAgentConfig;
|
||||||
import android.net.NetworkCapabilities;
|
import android.net.NetworkCapabilities;
|
||||||
import android.net.NetworkProvider;
|
import android.net.NetworkProvider;
|
||||||
|
import android.net.NetworkScore;
|
||||||
import android.net.RouteInfo;
|
import android.net.RouteInfo;
|
||||||
import android.net.TelephonyNetworkSpecifier;
|
import android.net.TelephonyNetworkSpecifier;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
@@ -517,6 +520,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 +630,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 +649,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 +657,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 +1510,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 +1523,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 +1851,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 +1862,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2040,6 +2055,12 @@ public class VcnGatewayConnection extends StateMachine {
|
|||||||
"mNetworkAgent.getNetwork(): "
|
"mNetworkAgent.getNetwork(): "
|
||||||
+ (mNetworkAgent == null ? null : mNetworkAgent.getNetwork()));
|
+ (mNetworkAgent == null ? null : mNetworkAgent.getNetwork()));
|
||||||
|
|
||||||
|
pw.println("mUnderlying:");
|
||||||
|
pw.increaseIndent();
|
||||||
|
mUnderlying.dump(pw);
|
||||||
|
pw.decreaseIndent();
|
||||||
|
pw.println();
|
||||||
|
|
||||||
pw.decreaseIndent();
|
pw.decreaseIndent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2183,7 +2204,7 @@ public class VcnGatewayConnection extends StateMachine {
|
|||||||
@NonNull String tag,
|
@NonNull String tag,
|
||||||
@NonNull NetworkCapabilities caps,
|
@NonNull NetworkCapabilities caps,
|
||||||
@NonNull LinkProperties lp,
|
@NonNull LinkProperties lp,
|
||||||
@NonNull int score,
|
@NonNull NetworkScore score,
|
||||||
@NonNull NetworkAgentConfig nac,
|
@NonNull NetworkAgentConfig nac,
|
||||||
@NonNull NetworkProvider provider,
|
@NonNull NetworkProvider provider,
|
||||||
@NonNull Consumer<VcnNetworkAgent> networkUnwantedCallback,
|
@NonNull Consumer<VcnNetworkAgent> networkUnwantedCallback,
|
||||||
@@ -2324,7 +2345,7 @@ public class VcnGatewayConnection extends StateMachine {
|
|||||||
@NonNull String tag,
|
@NonNull String tag,
|
||||||
@NonNull NetworkCapabilities caps,
|
@NonNull NetworkCapabilities caps,
|
||||||
@NonNull LinkProperties lp,
|
@NonNull LinkProperties lp,
|
||||||
@NonNull int score,
|
@NonNull NetworkScore score,
|
||||||
@NonNull NetworkAgentConfig nac,
|
@NonNull NetworkAgentConfig nac,
|
||||||
@NonNull NetworkProvider provider,
|
@NonNull NetworkProvider provider,
|
||||||
@NonNull Consumer<VcnNetworkAgent> networkUnwantedCallback,
|
@NonNull Consumer<VcnNetworkAgent> networkUnwantedCallback,
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import android.content.Context;
|
|||||||
import android.net.NetworkProvider;
|
import android.net.NetworkProvider;
|
||||||
import android.net.NetworkRequest;
|
import android.net.NetworkRequest;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.util.ArrayMap;
|
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
|
|
||||||
@@ -31,7 +30,6 @@ import com.android.internal.annotations.VisibleForTesting;
|
|||||||
import com.android.internal.annotations.VisibleForTesting.Visibility;
|
import com.android.internal.annotations.VisibleForTesting.Visibility;
|
||||||
import com.android.internal.util.IndentingPrintWriter;
|
import com.android.internal.util.IndentingPrintWriter;
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -48,11 +46,11 @@ public class VcnNetworkProvider extends NetworkProvider {
|
|||||||
private final Set<NetworkRequestListener> mListeners = new ArraySet<>();
|
private final Set<NetworkRequestListener> mListeners = new ArraySet<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cache of NetworkRequest(s), scores and network providers, keyed by NetworkRequest
|
* Cache of NetworkRequest(s).
|
||||||
*
|
*
|
||||||
* <p>NetworkRequests are immutable once created, and therefore can be used as stable keys.
|
* <p>NetworkRequests are immutable once created, and therefore can be used as stable keys.
|
||||||
*/
|
*/
|
||||||
private final ArrayMap<NetworkRequest, NetworkRequestEntry> mRequests = new ArrayMap<>();
|
private final Set<NetworkRequest> mRequests = new ArraySet<>();
|
||||||
|
|
||||||
public VcnNetworkProvider(Context context, Looper looper) {
|
public VcnNetworkProvider(Context context, Looper looper) {
|
||||||
super(context, looper, VcnNetworkProvider.class.getSimpleName());
|
super(context, looper, VcnNetworkProvider.class.getSimpleName());
|
||||||
@@ -80,38 +78,28 @@ public class VcnNetworkProvider extends NetworkProvider {
|
|||||||
/** Sends all cached NetworkRequest(s) to the specified listener. */
|
/** Sends all cached NetworkRequest(s) to the specified listener. */
|
||||||
@VisibleForTesting(visibility = Visibility.PACKAGE)
|
@VisibleForTesting(visibility = Visibility.PACKAGE)
|
||||||
public void resendAllRequests(@NonNull NetworkRequestListener listener) {
|
public void resendAllRequests(@NonNull NetworkRequestListener listener) {
|
||||||
for (NetworkRequestEntry entry : mRequests.values()) {
|
for (NetworkRequest request : mRequests) {
|
||||||
notifyListenerForEvent(listener, entry);
|
notifyListenerForEvent(listener, request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyListenerForEvent(
|
private void notifyListenerForEvent(
|
||||||
@NonNull NetworkRequestListener listener, @NonNull NetworkRequestEntry entry) {
|
@NonNull NetworkRequestListener listener, @NonNull NetworkRequest request) {
|
||||||
listener.onNetworkRequested(entry.mRequest, entry.mScore, entry.mProviderId);
|
listener.onNetworkRequested(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) {
|
public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) {
|
||||||
if (VDBG) {
|
if (VDBG) {
|
||||||
Slog.v(
|
Slog.v(TAG, "Network requested: Request = " + request);
|
||||||
TAG,
|
|
||||||
"Network requested: Request = "
|
|
||||||
+ request
|
|
||||||
+ ", score = "
|
|
||||||
+ score
|
|
||||||
+ ", providerId = "
|
|
||||||
+ providerId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final NetworkRequestEntry entry = new NetworkRequestEntry(request, score, providerId);
|
mRequests.add(request);
|
||||||
|
|
||||||
// NetworkRequests are immutable once created, and therefore can be used as stable keys.
|
|
||||||
mRequests.put(request, entry);
|
|
||||||
|
|
||||||
// TODO(b/176939047): Intelligently route requests to prioritized VcnInstances (based on
|
// TODO(b/176939047): Intelligently route requests to prioritized VcnInstances (based on
|
||||||
// Default Data Sub, or similar)
|
// Default Data Sub, or similar)
|
||||||
for (NetworkRequestListener listener : mListeners) {
|
for (NetworkRequestListener listener : mListeners) {
|
||||||
notifyListenerForEvent(listener, entry);
|
notifyListenerForEvent(listener, request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,37 +108,9 @@ public class VcnNetworkProvider extends NetworkProvider {
|
|||||||
mRequests.remove(request);
|
mRequests.remove(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class NetworkRequestEntry {
|
|
||||||
public final NetworkRequest mRequest;
|
|
||||||
public final int mScore;
|
|
||||||
public final int mProviderId;
|
|
||||||
|
|
||||||
private NetworkRequestEntry(@NonNull NetworkRequest request, int score, int providerId) {
|
|
||||||
mRequest = Objects.requireNonNull(request, "Missing request");
|
|
||||||
mScore = score;
|
|
||||||
mProviderId = providerId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dumps the state of this NetworkRequestEntry for logging and debugging purposes.
|
|
||||||
*
|
|
||||||
* <p>PII and credentials MUST NEVER be dumped here.
|
|
||||||
*/
|
|
||||||
public void dump(IndentingPrintWriter pw) {
|
|
||||||
pw.println("NetworkRequestEntry:");
|
|
||||||
pw.increaseIndent();
|
|
||||||
|
|
||||||
pw.println("mRequest: " + mRequest);
|
|
||||||
pw.println("mScore: " + mScore);
|
|
||||||
pw.println("mProviderId: " + mProviderId);
|
|
||||||
|
|
||||||
pw.decreaseIndent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// package-private
|
// package-private
|
||||||
interface NetworkRequestListener {
|
interface NetworkRequestListener {
|
||||||
void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId);
|
void onNetworkRequested(@NonNull NetworkRequest request);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -163,15 +123,19 @@ public class VcnNetworkProvider extends NetworkProvider {
|
|||||||
pw.increaseIndent();
|
pw.increaseIndent();
|
||||||
|
|
||||||
pw.println("mListeners:");
|
pw.println("mListeners:");
|
||||||
|
pw.increaseIndent();
|
||||||
for (NetworkRequestListener listener : mListeners) {
|
for (NetworkRequestListener listener : mListeners) {
|
||||||
pw.println(listener);
|
pw.println(listener);
|
||||||
}
|
}
|
||||||
|
pw.decreaseIndent();
|
||||||
pw.println();
|
pw.println();
|
||||||
|
|
||||||
pw.println("mRequests.values:");
|
pw.println("mRequests:");
|
||||||
for (NetworkRequestEntry entry : mRequests.values()) {
|
pw.increaseIndent();
|
||||||
entry.dump(pw);
|
for (NetworkRequest request : mRequests) {
|
||||||
|
pw.println(request);
|
||||||
}
|
}
|
||||||
|
pw.decreaseIndent();
|
||||||
pw.println();
|
pw.println();
|
||||||
|
|
||||||
pw.decreaseIndent();
|
pw.decreaseIndent();
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import static org.junit.Assert.fail;
|
|||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.CALLS_REAL_METHODS;
|
||||||
import static org.mockito.Mockito.any;
|
import static org.mockito.Mockito.any;
|
||||||
import static org.mockito.Mockito.argThat;
|
import static org.mockito.Mockito.argThat;
|
||||||
import static org.mockito.Mockito.doAnswer;
|
import static org.mockito.Mockito.doAnswer;
|
||||||
@@ -59,7 +60,6 @@ import android.net.ConnectivityManager;
|
|||||||
import android.net.LinkProperties;
|
import android.net.LinkProperties;
|
||||||
import android.net.Network;
|
import android.net.Network;
|
||||||
import android.net.NetworkCapabilities;
|
import android.net.NetworkCapabilities;
|
||||||
import android.net.NetworkCapabilities.Transport;
|
|
||||||
import android.net.NetworkRequest;
|
import android.net.NetworkRequest;
|
||||||
import android.net.TelephonyNetworkSpecifier;
|
import android.net.TelephonyNetworkSpecifier;
|
||||||
import android.net.vcn.IVcnStatusCallback;
|
import android.net.vcn.IVcnStatusCallback;
|
||||||
@@ -657,7 +657,7 @@ public class VcnManagementServiceTest {
|
|||||||
|
|
||||||
private void verifyMergedNetworkCapabilities(
|
private void verifyMergedNetworkCapabilities(
|
||||||
NetworkCapabilities mergedCapabilities,
|
NetworkCapabilities mergedCapabilities,
|
||||||
@Transport int transportType,
|
int transportType,
|
||||||
boolean isVcnManaged,
|
boolean isVcnManaged,
|
||||||
boolean isRestricted) {
|
boolean isRestricted) {
|
||||||
assertTrue(mergedCapabilities.hasTransport(transportType));
|
assertTrue(mergedCapabilities.hasTransport(transportType));
|
||||||
@@ -779,7 +779,7 @@ public class VcnManagementServiceTest {
|
|||||||
.registerNetworkCallback(
|
.registerNetworkCallback(
|
||||||
eq(new NetworkRequest.Builder().clearCapabilities().build()),
|
eq(new NetworkRequest.Builder().clearCapabilities().build()),
|
||||||
captor.capture());
|
captor.capture());
|
||||||
captor.getValue().onCapabilitiesChanged(new Network(0), caps);
|
captor.getValue().onCapabilitiesChanged(mock(Network.class, CALLS_REAL_METHODS), caps);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
|
|||||||
mNetworkAgent = mock(VcnNetworkAgent.class);
|
mNetworkAgent = mock(VcnNetworkAgent.class);
|
||||||
doReturn(mNetworkAgent)
|
doReturn(mNetworkAgent)
|
||||||
.when(mDeps)
|
.when(mDeps)
|
||||||
.newNetworkAgent(any(), any(), any(), any(), anyInt(), any(), any(), any(), any());
|
.newNetworkAgent(any(), any(), any(), any(), any(), any(), any(), any(), any());
|
||||||
|
|
||||||
mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1);
|
mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1);
|
||||||
|
|
||||||
@@ -216,7 +216,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
|
|||||||
any(),
|
any(),
|
||||||
any(),
|
any(),
|
||||||
any(),
|
any(),
|
||||||
anyInt(),
|
any(),
|
||||||
any(),
|
any(),
|
||||||
any(),
|
any(),
|
||||||
any(),
|
any(),
|
||||||
@@ -244,7 +244,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
|
|||||||
any(String.class),
|
any(String.class),
|
||||||
ncCaptor.capture(),
|
ncCaptor.capture(),
|
||||||
lpCaptor.capture(),
|
lpCaptor.capture(),
|
||||||
anyInt(),
|
any(),
|
||||||
argThat(nac -> nac.getLegacyType() == ConnectivityManager.TYPE_MOBILE),
|
argThat(nac -> nac.getLegacyType() == ConnectivityManager.TYPE_MOBILE),
|
||||||
any(),
|
any(),
|
||||||
any(),
|
any(),
|
||||||
@@ -297,7 +297,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
|
|||||||
startingInternalAddrs.equals(lp.getLinkAddresses())
|
startingInternalAddrs.equals(lp.getLinkAddresses())
|
||||||
&& Collections.singletonList(TEST_DNS_ADDR)
|
&& Collections.singletonList(TEST_DNS_ADDR)
|
||||||
.equals(lp.getDnsServers())),
|
.equals(lp.getDnsServers())),
|
||||||
anyInt(),
|
any(),
|
||||||
any(),
|
any(),
|
||||||
any(),
|
any(),
|
||||||
any(),
|
any(),
|
||||||
@@ -356,7 +356,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
|
|||||||
any(),
|
any(),
|
||||||
any(),
|
any(),
|
||||||
any(),
|
any(),
|
||||||
anyInt(),
|
any(),
|
||||||
any(),
|
any(),
|
||||||
any(),
|
any(),
|
||||||
unwantedCallbackCaptor.capture(),
|
unwantedCallbackCaptor.capture(),
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -25,7 +27,10 @@ import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
|
|||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyLong;
|
||||||
import static org.mockito.Matchers.eq;
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Mockito.CALLS_REAL_METHODS;
|
||||||
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
@@ -83,34 +88,46 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase {
|
|||||||
super.setUp();
|
super.setUp();
|
||||||
|
|
||||||
mWifiInfo = mock(WifiInfo.class);
|
mWifiInfo = mock(WifiInfo.class);
|
||||||
|
doReturn(mWifiInfo).when(mWifiInfo).makeCopy(anyLong());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void verifyBuildNetworkCapabilitiesCommon(int transportType) {
|
private void verifyBuildNetworkCapabilitiesCommon(
|
||||||
final NetworkCapabilities underlyingCaps = new NetworkCapabilities();
|
int transportType, boolean isMobileDataEnabled) {
|
||||||
underlyingCaps.addTransportType(transportType);
|
final NetworkCapabilities.Builder capBuilder = new NetworkCapabilities.Builder();
|
||||||
underlyingCaps.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
|
capBuilder.addTransportType(transportType);
|
||||||
underlyingCaps.addCapability(NET_CAPABILITY_NOT_METERED);
|
capBuilder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
|
||||||
underlyingCaps.addCapability(NET_CAPABILITY_NOT_ROAMING);
|
capBuilder.addCapability(NET_CAPABILITY_NOT_METERED);
|
||||||
|
capBuilder.addCapability(NET_CAPABILITY_NOT_ROAMING);
|
||||||
|
|
||||||
if (transportType == TRANSPORT_WIFI) {
|
if (transportType == TRANSPORT_WIFI) {
|
||||||
underlyingCaps.setTransportInfo(mWifiInfo);
|
capBuilder.setTransportInfo(mWifiInfo);
|
||||||
underlyingCaps.setOwnerUid(TEST_UID);
|
capBuilder.setOwnerUid(TEST_UID);
|
||||||
} else if (transportType == TRANSPORT_CELLULAR) {
|
} else if (transportType == TRANSPORT_CELLULAR) {
|
||||||
underlyingCaps.setAdministratorUids(new int[] {TEST_UID});
|
capBuilder.setNetworkSpecifier(
|
||||||
underlyingCaps.setNetworkSpecifier(
|
|
||||||
new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID_1));
|
new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID_1));
|
||||||
}
|
}
|
||||||
|
capBuilder.setAdministratorUids(new int[] {TEST_UID});
|
||||||
UnderlyingNetworkRecord record =
|
UnderlyingNetworkRecord record = new UnderlyingNetworkRecord(
|
||||||
new UnderlyingNetworkRecord(
|
mock(Network.class, CALLS_REAL_METHODS),
|
||||||
new Network(0), underlyingCaps, 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);
|
||||||
|
|
||||||
@@ -124,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
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import static org.junit.Assert.assertNull;
|
|||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.Matchers.any;
|
||||||
import static org.mockito.Matchers.eq;
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Mockito.CALLS_REAL_METHODS;
|
||||||
import static org.mockito.Mockito.atLeastOnce;
|
import static org.mockito.Mockito.atLeastOnce;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
@@ -93,7 +94,7 @@ public class VcnGatewayConnectionTestBase {
|
|||||||
|
|
||||||
protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 =
|
protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 =
|
||||||
new UnderlyingNetworkRecord(
|
new UnderlyingNetworkRecord(
|
||||||
new Network(0),
|
mock(Network.class, CALLS_REAL_METHODS),
|
||||||
new NetworkCapabilities(),
|
new NetworkCapabilities(),
|
||||||
new LinkProperties(),
|
new LinkProperties(),
|
||||||
false /* blocked */);
|
false /* blocked */);
|
||||||
@@ -104,7 +105,7 @@ public class VcnGatewayConnectionTestBase {
|
|||||||
|
|
||||||
protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_2 =
|
protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_2 =
|
||||||
new UnderlyingNetworkRecord(
|
new UnderlyingNetworkRecord(
|
||||||
new Network(1),
|
mock(Network.class, CALLS_REAL_METHODS),
|
||||||
new NetworkCapabilities(),
|
new NetworkCapabilities(),
|
||||||
new LinkProperties(),
|
new LinkProperties(),
|
||||||
false /* blocked */);
|
false /* blocked */);
|
||||||
@@ -201,6 +202,7 @@ public class VcnGatewayConnectionTestBase {
|
|||||||
TEST_SUBSCRIPTION_SNAPSHOT,
|
TEST_SUBSCRIPTION_SNAPSHOT,
|
||||||
mConfig,
|
mConfig,
|
||||||
mGatewayStatusCallback,
|
mGatewayStatusCallback,
|
||||||
|
true /* isMobileDataEnabled */,
|
||||||
mDeps);
|
mDeps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,6 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
|
|||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.ConnectivityManager;
|
|
||||||
import android.net.NetworkCapabilities;
|
|
||||||
import android.net.NetworkRequest;
|
import android.net.NetworkRequest;
|
||||||
import android.os.test.TestLooper;
|
import android.os.test.TestLooper;
|
||||||
|
|
||||||
@@ -44,10 +42,7 @@ import java.util.List;
|
|||||||
@SmallTest
|
@SmallTest
|
||||||
public class VcnNetworkProviderTest {
|
public class VcnNetworkProviderTest {
|
||||||
private static final int TEST_SCORE_UNSATISFIED = 0;
|
private static final int TEST_SCORE_UNSATISFIED = 0;
|
||||||
private static final int TEST_SCORE_HIGH = 100;
|
|
||||||
private static final int TEST_PROVIDER_ID = 1;
|
private static final int TEST_PROVIDER_ID = 1;
|
||||||
private static final int TEST_LEGACY_TYPE = ConnectivityManager.TYPE_MOBILE;
|
|
||||||
private static final NetworkRequest.Type TEST_REQUEST_TYPE = NetworkRequest.Type.REQUEST;
|
|
||||||
|
|
||||||
@NonNull private final Context mContext;
|
@NonNull private final Context mContext;
|
||||||
@NonNull private final TestLooper mTestLooper;
|
@NonNull private final TestLooper mTestLooper;
|
||||||
@@ -72,17 +67,7 @@ public class VcnNetworkProviderTest {
|
|||||||
|
|
||||||
final NetworkRequest request = mock(NetworkRequest.class);
|
final NetworkRequest request = mock(NetworkRequest.class);
|
||||||
mVcnNetworkProvider.onNetworkRequested(request, TEST_SCORE_UNSATISFIED, TEST_PROVIDER_ID);
|
mVcnNetworkProvider.onNetworkRequested(request, TEST_SCORE_UNSATISFIED, TEST_PROVIDER_ID);
|
||||||
verify(mListener).onNetworkRequested(request, TEST_SCORE_UNSATISFIED, TEST_PROVIDER_ID);
|
verify(mListener).onNetworkRequested(request);
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRequestsPassedToRegisteredListeners_satisfiedByHighScoringProvider()
|
|
||||||
throws Exception {
|
|
||||||
mVcnNetworkProvider.registerListener(mListener);
|
|
||||||
|
|
||||||
final NetworkRequest request = mock(NetworkRequest.class);
|
|
||||||
mVcnNetworkProvider.onNetworkRequested(request, TEST_SCORE_HIGH, TEST_PROVIDER_ID);
|
|
||||||
verify(mListener).onNetworkRequested(request, TEST_SCORE_HIGH, TEST_PROVIDER_ID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -100,21 +85,22 @@ public class VcnNetworkProviderTest {
|
|||||||
final List<NetworkRequest> requests = new ArrayList<>();
|
final List<NetworkRequest> requests = new ArrayList<>();
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
|
// Build unique network requests; in this case, iterate down the capabilities as a way
|
||||||
|
// to unique-ify requests.
|
||||||
final NetworkRequest request =
|
final NetworkRequest request =
|
||||||
new NetworkRequest(
|
new NetworkRequest.Builder().clearCapabilities().addCapability(i).build();
|
||||||
new NetworkCapabilities(),
|
|
||||||
TEST_LEGACY_TYPE,
|
|
||||||
i /* requestId */,
|
|
||||||
TEST_REQUEST_TYPE);
|
|
||||||
|
|
||||||
requests.add(request);
|
requests.add(request);
|
||||||
mVcnNetworkProvider.onNetworkRequested(request, i, i + 1);
|
mVcnNetworkProvider.onNetworkRequested(request, i, i + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove one, and verify that it is never sent to the listeners.
|
||||||
|
final NetworkRequest removed = requests.remove(0);
|
||||||
|
mVcnNetworkProvider.onNetworkRequestWithdrawn(removed);
|
||||||
|
|
||||||
mVcnNetworkProvider.registerListener(mListener);
|
mVcnNetworkProvider.registerListener(mListener);
|
||||||
for (int i = 0; i < requests.size(); i++) {
|
for (NetworkRequest request : requests) {
|
||||||
final NetworkRequest request = requests.get(i);
|
verify(mListener).onNetworkRequested(request);
|
||||||
verify(mListener).onNetworkRequested(request, i, i + 1);
|
|
||||||
}
|
}
|
||||||
verifyNoMoreInteractions(mListener);
|
verifyNoMoreInteractions(mListener);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,23 +65,31 @@ 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;
|
||||||
|
|
||||||
public class VcnTest {
|
public class VcnTest {
|
||||||
private static final String PKG_NAME = VcnTest.class.getPackage().getName();
|
private static final String PKG_NAME = VcnTest.class.getPackage().getName();
|
||||||
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 boolean MOBILE_DATA_ENABLED = true;
|
||||||
private static final int PROVIDER_ID = 5;
|
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 +106,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 +120,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 +149,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);
|
||||||
@@ -139,7 +175,7 @@ public class VcnTest {
|
|||||||
requestBuilder.addCapability(netCapability);
|
requestBuilder.addCapability(netCapability);
|
||||||
}
|
}
|
||||||
|
|
||||||
requestListener.onNetworkRequested(requestBuilder.build(), NETWORK_SCORE, PROVIDER_ID);
|
requestListener.onNetworkRequested(requestBuilder.build());
|
||||||
mTestLooper.dispatchAll();
|
mTestLooper.dispatchAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,6 +199,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 +262,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 +326,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 +357,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 +380,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