Merge "MediaDrm: error detail apis"
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index f494fa6..db1db91 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -1019,9 +1019,10 @@
registerService(Context.APPWIDGET_SERVICE, AppWidgetManager.class,
new CachedServiceFetcher<AppWidgetManager>() {
@Override
- public AppWidgetManager createService(ContextImpl ctx) throws ServiceNotFoundException {
- IBinder b = ServiceManager.getServiceOrThrow(Context.APPWIDGET_SERVICE);
- return new AppWidgetManager(ctx, IAppWidgetService.Stub.asInterface(b));
+ public AppWidgetManager createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(Context.APPWIDGET_SERVICE);
+ return b == null ? null : new AppWidgetManager(ctx,
+ IAppWidgetService.Stub.asInterface(b));
}});
registerService(Context.MIDI_SERVICE, MidiManager.class,
diff --git a/core/java/android/app/servertransaction/TransactionExecutorHelper.java b/core/java/android/app/servertransaction/TransactionExecutorHelper.java
index 92f7dee..cb6aa09 100644
--- a/core/java/android/app/servertransaction/TransactionExecutorHelper.java
+++ b/core/java/android/app/servertransaction/TransactionExecutorHelper.java
@@ -31,6 +31,7 @@
import android.app.ClientTransactionHandler;
import android.os.IBinder;
import android.util.IntArray;
+import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -43,6 +44,7 @@
* @hide
*/
public class TransactionExecutorHelper {
+ private static final String TAG = TransactionExecutorHelper.class.getSimpleName();
// A penalty applied to path with destruction when looking for the shortest one.
private static final int DESTRUCTION_PENALTY = 10;
@@ -162,6 +164,11 @@
if (finalStates == null || finalStates.length == 0) {
return UNDEFINED;
}
+ if (r == null) {
+ // Early return because the ActivityClientRecord hasn't been created or cannot be found.
+ Log.w(TAG, "ActivityClientRecord was null");
+ return UNDEFINED;
+ }
final int currentState = r.getLifecycleState();
int closestState = UNDEFINED;
diff --git a/core/java/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java b/core/java/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java
index c3dba33..38b3174 100644
--- a/core/java/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java
+++ b/core/java/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java
@@ -353,6 +353,11 @@
return mCapabilitiesMatchCriteria.get(NET_CAPABILITY_RCS);
}
+ /** @hide */
+ public Map<Integer, Integer> getCapabilitiesMatchCriteria() {
+ return Collections.unmodifiableMap(new HashMap<>(mCapabilitiesMatchCriteria));
+ }
+
@Override
public int hashCode() {
return Objects.hash(
diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index 3a7aea5..70cf973 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -114,13 +114,28 @@
public static final String VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY =
"vcn_restricted_transports";
+ /**
+ * Key for maximum number of parallel SAs for tunnel aggregation
+ *
+ * <p>If set to a value > 1, multiple tunnels will be set up, and inbound traffic will be
+ * aggregated over the various tunnels.
+ *
+ * <p>Defaults to 1, unless overridden by carrier config
+ *
+ * @hide
+ */
+ @NonNull
+ public static final String VCN_TUNNEL_AGGREGATION_SA_COUNT_MAX_KEY =
+ "vcn_tunnel_aggregation_sa_count_max";
+
/** List of Carrier Config options to extract from Carrier Config bundles. @hide */
@NonNull
public static final String[] VCN_RELATED_CARRIER_CONFIG_KEYS =
new String[] {
VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY,
VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY,
- VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY
+ VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY,
+ VCN_TUNNEL_AGGREGATION_SA_COUNT_MAX_KEY,
};
private static final Map<
diff --git a/core/java/android/view/autofill/OWNERS b/core/java/android/view/autofill/OWNERS
index 108c42c..26c59a6 100644
--- a/core/java/android/view/autofill/OWNERS
+++ b/core/java/android/view/autofill/OWNERS
@@ -1,7 +1,10 @@
# Bug component: 351486
augale@google.com
+haoranzhang@google.com
joannechung@google.com
markpun@google.com
lpeter@google.com
+simranjit@google.com
tymtsai@google.com
+yunicorn@google.com
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 949f363..7dd46a6 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -640,7 +640,6 @@
char jitmaxsizeOptsBuf[sizeof("-Xjitmaxsize:")-1 + PROPERTY_VALUE_MAX];
char jitinitialsizeOptsBuf[sizeof("-Xjitinitialsize:")-1 + PROPERTY_VALUE_MAX];
char jitthresholdOptsBuf[sizeof("-Xjitthreshold:")-1 + PROPERTY_VALUE_MAX];
- char useJitProfilesOptsBuf[sizeof("-Xjitsaveprofilinginfo:")-1 + PROPERTY_VALUE_MAX];
char jitprithreadweightOptBuf[sizeof("-Xjitprithreadweight:")-1 + PROPERTY_VALUE_MAX];
char jittransitionweightOptBuf[sizeof("-Xjittransitionweight:")-1 + PROPERTY_VALUE_MAX];
char hotstartupsamplesOptsBuf[sizeof("-Xps-hot-startup-method-samples:")-1 + PROPERTY_VALUE_MAX];
@@ -856,10 +855,7 @@
parseRuntimeOption("dalvik.vm.jitpthreadpriority",
jitpthreadpriorityOptsBuf,
"-Xjitpthreadpriority:");
- property_get("dalvik.vm.usejitprofiles", useJitProfilesOptsBuf, "");
- if (strcmp(useJitProfilesOptsBuf, "true") == 0) {
- addOption("-Xjitsaveprofilinginfo");
- }
+ addOption("-Xjitsaveprofilinginfo");
parseRuntimeOption("dalvik.vm.jitprithreadweight",
jitprithreadweightOptBuf,
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index 1327d96..ea2b988 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -17,12 +17,6 @@
<resources>
<!-- This file defines Android telephony related resources -->
- <!-- Whether force disabling telephony new data stack or not.
- This flag and the old data stack code will be deleted in Android 14.
- -->
- <bool name="config_force_disable_telephony_new_data_stack">false</bool>
- <java-symbol type="bool" name="config_force_disable_telephony_new_data_stack" />
-
<!-- Configure tcp buffer sizes per network type in the form:
network-type:rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/AppIconCacheManager.java b/packages/SettingsLib/src/com/android/settingslib/applications/AppIconCacheManager.java
index 9dfc8ea..c0117b9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/AppIconCacheManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/AppIconCacheManager.java
@@ -22,13 +22,16 @@
import android.util.Log;
import android.util.LruCache;
+import androidx.annotation.VisibleForTesting;
+
/**
* Cache app icon for management.
*/
public class AppIconCacheManager {
private static final String TAG = "AppIconCacheManager";
private static final float CACHE_RATIO = 0.1f;
- private static final int MAX_CACHE_SIZE_IN_KB = getMaxCacheInKb();
+ @VisibleForTesting
+ static final int MAX_CACHE_SIZE_IN_KB = getMaxCacheInKb();
private static final String DELIMITER = ":";
private static AppIconCacheManager sAppIconCacheManager;
private final LruCache<String, Drawable> mDrawableCache;
@@ -109,4 +112,25 @@
private static int getMaxCacheInKb() {
return Math.round(CACHE_RATIO * Runtime.getRuntime().maxMemory() / 1024);
}
+
+ /**
+ * Clears as much memory as possible.
+ *
+ * @see android.content.ComponentCallbacks2#onTrimMemory(int)
+ */
+ public void trimMemory(int level) {
+ if (level >= android.content.ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {
+ // Time to clear everything
+ if (sAppIconCacheManager != null) {
+ sAppIconCacheManager.mDrawableCache.trimToSize(0);
+ }
+ } else if (level >= android.content.ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
+ || level == android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL) {
+ // Tough time but still affordable, clear half of the cache
+ if (sAppIconCacheManager != null) {
+ final int maxSize = sAppIconCacheManager.mDrawableCache.maxSize();
+ sAppIconCacheManager.mDrawableCache.trimToSize(maxSize / 2);
+ }
+ }
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/AppIconCacheManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/AppIconCacheManagerTest.java
index 64f8bef..1b0e1f1 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/AppIconCacheManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/AppIconCacheManagerTest.java
@@ -34,11 +34,21 @@
public class AppIconCacheManagerTest {
private static final String APP_PACKAGE_NAME = "com.test.app";
+ private static final String APP_PACKAGE_NAME1 = "com.test.app1";
+ private static final String APP_PACKAGE_NAME2 = "com.test.app2";
+ private static final String APP_PACKAGE_NAME3 = "com.test.app3";
private static final int APP_UID = 9999;
@Mock
private Drawable mIcon;
+ @Mock
+ private Drawable mIcon1;
+ @Mock
+ private Drawable mIcon2;
+ @Mock
+ private Drawable mIcon3;
+
private AppIconCacheManager mAppIconCacheManager;
@Before
@@ -48,6 +58,29 @@
doReturn(10).when(mIcon).getIntrinsicHeight();
doReturn(10).when(mIcon).getIntrinsicWidth();
doReturn(mIcon).when(mIcon).mutate();
+
+ // Algorithm for trim memory test:
+ // The real maxsize is defined by AppIconCacheManager.MAX_CACHE_SIZE_IN_KB, and the size
+ // of each element is calculated as following:
+ // n * n * 4 / 1024
+ // In the testcase, we want to mock the maxsize of LruCache is 3, so the formula calculating
+ // the size of each element will be like:
+ // n * n * 4 / 1024 = maxsize / 3
+ // Thus, n = square_root(maxsize / 3 * 1024 / 4), which can be used as an icon size.
+ final int iconSize =
+ (int) Math.sqrt(AppIconCacheManager.MAX_CACHE_SIZE_IN_KB / 3f * 1024f / 4f);
+
+ doReturn(iconSize).when(mIcon1).getIntrinsicHeight();
+ doReturn(iconSize).when(mIcon1).getIntrinsicWidth();
+ doReturn(mIcon1).when(mIcon1).mutate();
+
+ doReturn(iconSize).when(mIcon2).getIntrinsicHeight();
+ doReturn(iconSize).when(mIcon2).getIntrinsicWidth();
+ doReturn(mIcon2).when(mIcon2).mutate();
+
+ doReturn(iconSize).when(mIcon3).getIntrinsicHeight();
+ doReturn(iconSize).when(mIcon3).getIntrinsicWidth();
+ doReturn(mIcon3).when(mIcon3).mutate();
}
@After
@@ -106,4 +139,41 @@
assertThat(mAppIconCacheManager.get(APP_PACKAGE_NAME, APP_UID)).isNull();
}
+
+ @Test
+ public void trimMemory_levelSatisfied_shouldNotCacheIcon() {
+
+ mAppIconCacheManager.put(APP_PACKAGE_NAME1, APP_UID, mIcon1);
+ mAppIconCacheManager.put(APP_PACKAGE_NAME2, APP_UID, mIcon2);
+ mAppIconCacheManager.put(APP_PACKAGE_NAME3, APP_UID, mIcon3);
+
+ // Expected to trim size to 0
+ final int level = android.content.ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
+ mAppIconCacheManager.trimMemory(level);
+
+ // None of the elements should be cached
+ assertThat(mAppIconCacheManager.get(APP_PACKAGE_NAME1, APP_UID)).isNull();
+ assertThat(mAppIconCacheManager.get(APP_PACKAGE_NAME2, APP_UID)).isNull();
+ assertThat(mAppIconCacheManager.get(APP_PACKAGE_NAME3, APP_UID)).isNull();
+ }
+
+ @Test
+ public void trimMemory_levelSatisfied_shouldCacheAtLeastHalf() {
+
+ mAppIconCacheManager.put(APP_PACKAGE_NAME1, APP_UID, mIcon1);
+ mAppIconCacheManager.put(APP_PACKAGE_NAME2, APP_UID, mIcon2);
+ mAppIconCacheManager.put(APP_PACKAGE_NAME3, APP_UID, mIcon3);
+
+ // Get the last element
+ mAppIconCacheManager.get(APP_PACKAGE_NAME1, APP_UID);
+
+ // Expected to trim size to half of it, which is int( 3 / 2 ) = 1
+ final int level = android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL;
+ mAppIconCacheManager.trimMemory(level);
+
+ // There should be only one cached element, which is the last recently used one
+ assertThat(mAppIconCacheManager.get(APP_PACKAGE_NAME1, APP_UID)).isNotNull();
+ assertThat(mAppIconCacheManager.get(APP_PACKAGE_NAME2, APP_UID)).isNull();
+ assertThat(mAppIconCacheManager.get(APP_PACKAGE_NAME3, APP_UID)).isNull();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/OWNERS b/packages/SystemUI/tests/src/com/android/systemui/notetask/OWNERS
new file mode 100644
index 0000000..7ccb316
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/OWNERS
@@ -0,0 +1,8 @@
+# Bug component: 1254381
+azappone@google.com
+achalke@google.com
+juliacr@google.com
+madym@google.com
+mgalhardo@google.com
+petrcermak@google.com
+vanjan@google.com
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/stylus/OWNERS b/packages/SystemUI/tests/src/com/android/systemui/stylus/OWNERS
new file mode 100644
index 0000000..7ccb316
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/stylus/OWNERS
@@ -0,0 +1,8 @@
+# Bug component: 1254381
+azappone@google.com
+achalke@google.com
+juliacr@google.com
+madym@google.com
+mgalhardo@google.com
+petrcermak@google.com
+vanjan@google.com
\ No newline at end of file
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 430186a..6503029 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -2797,7 +2797,11 @@
try {
pvr = verifyAndGetBypass(uid, packageName, null);
} catch (SecurityException e) {
- Slog.e(TAG, "Cannot setMode", e);
+ if (Process.isIsolated(uid)) {
+ Slog.e(TAG, "Cannot setMode: isolated process");
+ } else {
+ Slog.e(TAG, "Cannot setMode", e);
+ }
return;
}
@@ -3252,7 +3256,11 @@
try {
pvr = verifyAndGetBypass(uid, packageName, null);
} catch (SecurityException e) {
- Slog.e(TAG, "checkOperation", e);
+ if (Process.isIsolated(uid)) {
+ Slog.e(TAG, "Cannot checkOperation: isolated process");
+ } else {
+ Slog.e(TAG, "Cannot checkOperation", e);
+ }
return AppOpsManager.opToDefaultMode(code);
}
@@ -3458,7 +3466,11 @@
attributionTag = null;
}
} catch (SecurityException e) {
- Slog.e(TAG, "noteOperation", e);
+ if (Process.isIsolated(uid)) {
+ Slog.e(TAG, "Cannot noteOperation: isolated process");
+ } else {
+ Slog.e(TAG, "Cannot noteOperation", e);
+ }
return new SyncNotedAppOp(AppOpsManager.MODE_ERRORED, code, attributionTag,
packageName);
}
@@ -3974,7 +3986,11 @@
attributionTag = null;
}
} catch (SecurityException e) {
- Slog.e(TAG, "startOperation", e);
+ if (Process.isIsolated(uid)) {
+ Slog.e(TAG, "Cannot startOperation: isolated process");
+ } else {
+ Slog.e(TAG, "Cannot startOperation", e);
+ }
return new SyncNotedAppOp(AppOpsManager.MODE_ERRORED, code, attributionTag,
packageName);
}
@@ -4148,7 +4164,11 @@
attributionTag = null;
}
} catch (SecurityException e) {
- Slog.e(TAG, "Cannot finishOperation", e);
+ if (Process.isIsolated(uid)) {
+ Slog.e(TAG, "Cannot finishOperation: isolated process");
+ } else {
+ Slog.e(TAG, "Cannot finishOperation", e);
+ }
return;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 1e64701..89719ce 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -1772,7 +1772,7 @@
private int runCompile() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
- boolean checkProfiles = SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
+ boolean checkProfiles = true;
boolean forceCompilation = false;
boolean allPackages = false;
boolean clearProfileData = false;
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index af507cd..50253ea 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -320,15 +320,13 @@
switch (profileType) {
case ArtManager.PROFILE_APPS :
- return SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
+ return true;
case ArtManager.PROFILE_BOOT_IMAGE:
// The device config property overrides the system property version.
boolean profileBootClassPath = SystemProperties.getBoolean(
"persist.device_config.runtime_native_boot.profilebootclasspath",
SystemProperties.getBoolean("dalvik.vm.profilebootclasspath", false));
- return (Build.IS_USERDEBUG || Build.IS_ENG) &&
- SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false) &&
- profileBootClassPath;
+ return (Build.IS_USERDEBUG || Build.IS_ENG) && profileBootClassPath;
default:
throw new IllegalArgumentException("Invalid profile type:" + profileType);
}
diff --git a/services/core/java/com/android/server/power/OWNERS b/services/core/java/com/android/server/power/OWNERS
index 5cbe74c..a0e91ad 100644
--- a/services/core/java/com/android/server/power/OWNERS
+++ b/services/core/java/com/android/server/power/OWNERS
@@ -1,4 +1,5 @@
michaelwr@google.com
santoscordon@google.com
+philipjunker@google.com
per-file ThermalManagerService.java=wvw@google.com
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 3be16a1..739aff7 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -33,6 +33,7 @@
import static com.android.server.VcnManagementService.LOCAL_LOG;
import static com.android.server.VcnManagementService.VDBG;
+import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -59,6 +60,7 @@
import android.net.TelephonyNetworkSpecifier;
import android.net.Uri;
import android.net.annotations.PolicyDirection;
+import android.net.ipsec.ike.ChildSaProposal;
import android.net.ipsec.ike.ChildSessionCallback;
import android.net.ipsec.ike.ChildSessionConfiguration;
import android.net.ipsec.ike.ChildSessionParams;
@@ -67,11 +69,14 @@
import android.net.ipsec.ike.IkeSessionConfiguration;
import android.net.ipsec.ike.IkeSessionConnectionInfo;
import android.net.ipsec.ike.IkeSessionParams;
+import android.net.ipsec.ike.IkeTrafficSelector;
import android.net.ipsec.ike.IkeTunnelConnectionParams;
+import android.net.ipsec.ike.TunnelModeChildSessionParams;
import android.net.ipsec.ike.exceptions.IkeException;
import android.net.ipsec.ike.exceptions.IkeInternalException;
import android.net.ipsec.ike.exceptions.IkeProtocolException;
import android.net.vcn.VcnGatewayConnectionConfig;
+import android.net.vcn.VcnManager;
import android.net.vcn.VcnTransportInfo;
import android.net.wifi.WifiInfo;
import android.os.Handler;
@@ -169,6 +174,9 @@
public class VcnGatewayConnection extends StateMachine {
private static final String TAG = VcnGatewayConnection.class.getSimpleName();
+ /** Default number of parallel SAs requested */
+ static final int TUNNEL_AGGREGATION_SA_COUNT_MAX_DEFAULT = 1;
+
// Matches DataConnection.NETWORK_TYPE private constant, and magic string from
// ConnectivityManager#getNetworkTypeName()
@VisibleForTesting(visibility = Visibility.PRIVATE)
@@ -1980,6 +1988,22 @@
mChildConfig,
oldChildConfig,
mIkeConnectionInfo);
+
+ // Create opportunistic child SAs; this allows SA aggregation in the downlink,
+ // reducing lock/atomic contention in high throughput scenarios. All SAs will
+ // share the same UDP encap socket (and keepalives) as necessary, and are
+ // effectively free.
+ final int parallelTunnelCount =
+ mDeps.getParallelTunnelCount(mLastSnapshot, mSubscriptionGroup);
+ logInfo("Parallel tunnel count: " + parallelTunnelCount);
+
+ for (int i = 0; i < parallelTunnelCount - 1; i++) {
+ mIkeSession.openChildSession(
+ buildOpportunisticChildParams(),
+ new VcnChildSessionCallback(
+ mCurrentToken, true /* isOpportunistic */));
+ }
+
break;
case EVENT_DISCONNECT_REQUESTED:
handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj);
@@ -2350,15 +2374,44 @@
@VisibleForTesting(visibility = Visibility.PRIVATE)
public class VcnChildSessionCallback implements ChildSessionCallback {
private final int mToken;
+ private final boolean mIsOpportunistic;
+
+ private boolean mIsChildOpened = false;
VcnChildSessionCallback(int token) {
+ this(token, false /* isOpportunistic */);
+ }
+
+ /**
+ * Creates a ChildSessionCallback
+ *
+ * <p>If configured as opportunistic, transforms will not report initial startup, or
+ * associated startup failures. This serves the dual purposes of ensuring that if the server
+ * does not support connection multiplexing, new child SA negotiations will be ignored, and
+ * at the same time, will notify the VCN session if a successfully negotiated opportunistic
+ * child SA is subsequently torn down, which could impact uplink traffic if the SA in use
+ * for outbound/uplink traffic is this opportunistic SA.
+ *
+ * <p>While inbound SAs can be used in parallel, the IPsec stack explicitly selects the last
+ * applied outbound transform for outbound traffic. This means that unlike inbound traffic,
+ * outbound does not benefit from these parallel SAs in the same manner.
+ */
+ VcnChildSessionCallback(int token, boolean isOpportunistic) {
mToken = token;
+ mIsOpportunistic = isOpportunistic;
}
/** Internal proxy method for injecting of mocked ChildSessionConfiguration */
@VisibleForTesting(visibility = Visibility.PRIVATE)
void onOpened(@NonNull VcnChildSessionConfiguration childConfig) {
logDbg("ChildOpened for token " + mToken);
+
+ if (mIsOpportunistic) {
+ logDbg("ChildOpened for opportunistic child; suppressing event message");
+ mIsChildOpened = true;
+ return;
+ }
+
childOpened(mToken, childConfig);
}
@@ -2370,12 +2423,24 @@
@Override
public void onClosed() {
logDbg("ChildClosed for token " + mToken);
+
+ if (mIsOpportunistic && !mIsChildOpened) {
+ logDbg("ChildClosed for unopened opportunistic child; ignoring");
+ return;
+ }
+
sessionLost(mToken, null);
}
@Override
public void onClosedExceptionally(@NonNull IkeException exception) {
logInfo("ChildClosedExceptionally for token " + mToken, exception);
+
+ if (mIsOpportunistic && !mIsChildOpened) {
+ logInfo("ChildClosedExceptionally for unopened opportunistic child; ignoring");
+ return;
+ }
+
sessionLost(mToken, exception);
}
@@ -2580,6 +2645,30 @@
return mConnectionConfig.getTunnelConnectionParams().getTunnelModeChildSessionParams();
}
+ private ChildSessionParams buildOpportunisticChildParams() {
+ final ChildSessionParams baseParams =
+ mConnectionConfig.getTunnelConnectionParams().getTunnelModeChildSessionParams();
+
+ final TunnelModeChildSessionParams.Builder builder =
+ new TunnelModeChildSessionParams.Builder();
+ for (ChildSaProposal proposal : baseParams.getChildSaProposals()) {
+ builder.addChildSaProposal(proposal);
+ }
+
+ for (IkeTrafficSelector inboundSelector : baseParams.getInboundTrafficSelectors()) {
+ builder.addInboundTrafficSelectors(inboundSelector);
+ }
+
+ for (IkeTrafficSelector outboundSelector : baseParams.getOutboundTrafficSelectors()) {
+ builder.addOutboundTrafficSelectors(outboundSelector);
+ }
+
+ builder.setLifetimeSeconds(
+ baseParams.getHardLifetimeSeconds(), baseParams.getSoftLifetimeSeconds());
+
+ return builder.build();
+ }
+
@VisibleForTesting(visibility = Visibility.PRIVATE)
VcnIkeSession buildIkeSession(@NonNull Network network) {
final int token = ++mCurrentToken;
@@ -2680,6 +2769,23 @@
return 0;
}
}
+
+ /** Gets the max number of parallel tunnels allowed for tunnel aggregation. */
+ public int getParallelTunnelCount(
+ TelephonySubscriptionSnapshot snapshot, ParcelUuid subGrp) {
+ PersistableBundleWrapper carrierConfig = snapshot.getCarrierConfigForSubGrp(subGrp);
+ int result = TUNNEL_AGGREGATION_SA_COUNT_MAX_DEFAULT;
+
+ if (carrierConfig != null) {
+ result =
+ carrierConfig.getInt(
+ VcnManager.VCN_TUNNEL_AGGREGATION_SA_COUNT_MAX_KEY,
+ TUNNEL_AGGREGATION_SA_COUNT_MAX_DEFAULT);
+ }
+
+ // Guard against tunnel count < 1
+ return Math.max(1, result);
+ }
}
/**
diff --git a/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java b/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java
index 2f84fdd..2141eba 100644
--- a/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java
+++ b/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java
@@ -15,6 +15,7 @@
*/
package com.android.server.vcn.routeselection;
+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.TRANSPORT_CELLULAR;
@@ -45,6 +46,7 @@
import com.android.server.vcn.VcnContext;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -69,9 +71,23 @@
@VisibleForTesting(visibility = Visibility.PRIVATE)
static final int WIFI_EXIT_RSSI_THRESHOLD_DEFAULT = -74;
- /** Priority for any other networks (including unvalidated, etc) */
+ /**
+ * Priority for networks that VCN can fall back to.
+ *
+ * <p>If none of the network candidates are validated or match any template, VCN will fall back
+ * to any INTERNET network.
+ */
@VisibleForTesting(visibility = Visibility.PRIVATE)
- static final int PRIORITY_ANY = Integer.MAX_VALUE;
+ static final int PRIORITY_FALLBACK = Integer.MAX_VALUE;
+
+ /**
+ * Priority for networks that cannot be selected as VCN's underlying networks.
+ *
+ * <p>VCN MUST never select a non-INTERNET network that are unvalidated or fail to match any
+ * template as the underlying network.
+ */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ static final int PRIORITY_INVALID = -1;
/** Gives networks a priority class, based on configured VcnGatewayConnectionConfig */
public static int calculatePriorityClass(
@@ -86,12 +102,12 @@
if (networkRecord.isBlocked) {
logWtf("Network blocked for System Server: " + networkRecord.network);
- return PRIORITY_ANY;
+ return PRIORITY_INVALID;
}
if (snapshot == null) {
logWtf("Got null snapshot");
- return PRIORITY_ANY;
+ return PRIORITY_INVALID;
}
int priorityIndex = 0;
@@ -108,7 +124,13 @@
}
priorityIndex++;
}
- return PRIORITY_ANY;
+
+ final NetworkCapabilities caps = networkRecord.networkCapabilities;
+ if (caps.hasCapability(NET_CAPABILITY_INTERNET)
+ || (vcnContext.isInTestMode() && caps.hasTransport(TRANSPORT_TEST))) {
+ return PRIORITY_FALLBACK;
+ }
+ return PRIORITY_INVALID;
}
@VisibleForTesting(visibility = Visibility.PRIVATE)
@@ -297,6 +319,18 @@
return false;
}
+ for (Map.Entry<Integer, Integer> entry :
+ networkPriority.getCapabilitiesMatchCriteria().entrySet()) {
+ final int cap = entry.getKey();
+ final int matchCriteria = entry.getValue();
+
+ if (matchCriteria == MATCH_REQUIRED && !caps.hasCapability(cap)) {
+ return false;
+ } else if (matchCriteria == MATCH_FORBIDDEN && caps.hasCapability(cap)) {
+ return false;
+ }
+ }
+
return true;
}
diff --git a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java
index d474c5d..6afa795 100644
--- a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java
+++ b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java
@@ -16,6 +16,9 @@
package com.android.server.vcn.routeselection;
+import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY;
+import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN;
+import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED;
import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener;
import static com.android.server.VcnManagementService.LOCAL_LOG;
@@ -32,6 +35,7 @@
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.TelephonyNetworkSpecifier;
+import android.net.vcn.VcnCellUnderlyingNetworkTemplate;
import android.net.vcn.VcnGatewayConnectionConfig;
import android.net.vcn.VcnUnderlyingNetworkTemplate;
import android.os.Handler;
@@ -40,6 +44,7 @@
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
@@ -49,6 +54,7 @@
import com.android.server.vcn.util.LogUtils;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -126,6 +132,63 @@
registerOrUpdateNetworkRequests();
}
+ private static class CapabilityMatchCriteria {
+ public final int capability;
+ public final int matchCriteria;
+
+ CapabilityMatchCriteria(int capability, int matchCriteria) {
+ this.capability = capability;
+ this.matchCriteria = matchCriteria;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(capability, matchCriteria);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object other) {
+ if (!(other instanceof CapabilityMatchCriteria)) {
+ return false;
+ }
+
+ final CapabilityMatchCriteria rhs = (CapabilityMatchCriteria) other;
+ return capability == rhs.capability && matchCriteria == rhs.matchCriteria;
+ }
+ }
+
+ private static Set<Set<CapabilityMatchCriteria>> dedupAndGetCapRequirementsForCell(
+ VcnGatewayConnectionConfig connectionConfig) {
+ final Set<Set<CapabilityMatchCriteria>> dedupedCapsMatchSets = new ArraySet<>();
+
+ for (VcnUnderlyingNetworkTemplate template :
+ connectionConfig.getVcnUnderlyingNetworkPriorities()) {
+ if (template instanceof VcnCellUnderlyingNetworkTemplate) {
+ final Set<CapabilityMatchCriteria> capsMatchSet = new ArraySet<>();
+
+ for (Map.Entry<Integer, Integer> entry :
+ ((VcnCellUnderlyingNetworkTemplate) template)
+ .getCapabilitiesMatchCriteria()
+ .entrySet()) {
+
+ final int capability = entry.getKey();
+ final int matchCriteria = entry.getValue();
+ if (matchCriteria != MATCH_ANY) {
+ capsMatchSet.add(new CapabilityMatchCriteria(capability, matchCriteria));
+ }
+ }
+
+ dedupedCapsMatchSets.add(capsMatchSet);
+ }
+ }
+
+ dedupedCapsMatchSets.add(
+ Collections.singleton(
+ new CapabilityMatchCriteria(
+ NetworkCapabilities.NET_CAPABILITY_INTERNET, MATCH_REQUIRED)));
+ return dedupedCapsMatchSets;
+ }
+
private void registerOrUpdateNetworkRequests() {
NetworkCallback oldRouteSelectionCallback = mRouteSelectionCallback;
NetworkCallback oldWifiCallback = mWifiBringupCallback;
@@ -158,11 +221,14 @@
getWifiNetworkRequest(), mWifiBringupCallback, mHandler);
for (final int subId : mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) {
- final NetworkBringupCallback cb = new NetworkBringupCallback();
- mCellBringupCallbacks.add(cb);
+ for (Set<CapabilityMatchCriteria> capsMatchCriteria :
+ dedupAndGetCapRequirementsForCell(mConnectionConfig)) {
+ final NetworkBringupCallback cb = new NetworkBringupCallback();
+ mCellBringupCallbacks.add(cb);
- mConnectivityManager.requestBackgroundNetwork(
- getCellNetworkRequestForSubId(subId), cb, mHandler);
+ mConnectivityManager.requestBackgroundNetwork(
+ getCellNetworkRequestForSubId(subId, capsMatchCriteria), cb, mHandler);
+ }
}
} else {
mRouteSelectionCallback = null;
@@ -214,6 +280,13 @@
.build();
}
+ private NetworkRequest.Builder getBaseWifiNetworkRequestBuilder() {
+ return getBaseNetworkRequestBuilder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup));
+ }
+
/**
* Builds the WiFi bringup request
*
@@ -224,10 +297,7 @@
* but will NEVER bring up a Carrier WiFi network itself.
*/
private NetworkRequest getWifiNetworkRequest() {
- return getBaseNetworkRequestBuilder()
- .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
- .setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup))
- .build();
+ return getBaseWifiNetworkRequestBuilder().build();
}
/**
@@ -238,9 +308,7 @@
* pace to effectively select a short-lived WiFi offload network.
*/
private NetworkRequest getWifiEntryRssiThresholdNetworkRequest() {
- return getBaseNetworkRequestBuilder()
- .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
- .setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup))
+ return getBaseWifiNetworkRequestBuilder()
// Ensure wifi updates signal strengths when crossing this threshold.
.setSignalStrength(getWifiEntryRssiThreshold(mCarrierConfig))
.build();
@@ -254,9 +322,7 @@
* pace to effectively select away from a failing WiFi network.
*/
private NetworkRequest getWifiExitRssiThresholdNetworkRequest() {
- return getBaseNetworkRequestBuilder()
- .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
- .setSubscriptionIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup))
+ return getBaseWifiNetworkRequestBuilder()
// Ensure wifi updates signal strengths when crossing this threshold.
.setSignalStrength(getWifiExitRssiThreshold(mCarrierConfig))
.build();
@@ -273,11 +339,25 @@
* <p>Since this request MUST make it to the TelephonyNetworkFactory, subIds are not specified
* in the NetworkCapabilities, but rather in the TelephonyNetworkSpecifier.
*/
- private NetworkRequest getCellNetworkRequestForSubId(int subId) {
- return getBaseNetworkRequestBuilder()
- .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
- .setNetworkSpecifier(new TelephonyNetworkSpecifier(subId))
- .build();
+ private NetworkRequest getCellNetworkRequestForSubId(
+ int subId, Set<CapabilityMatchCriteria> capsMatchCriteria) {
+ final NetworkRequest.Builder nrBuilder =
+ getBaseNetworkRequestBuilder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .setNetworkSpecifier(new TelephonyNetworkSpecifier(subId));
+
+ for (CapabilityMatchCriteria capMatchCriteria : capsMatchCriteria) {
+ final int cap = capMatchCriteria.capability;
+ final int matchCriteria = capMatchCriteria.matchCriteria;
+
+ if (matchCriteria == MATCH_REQUIRED) {
+ nrBuilder.addCapability(cap);
+ } else if (matchCriteria == MATCH_FORBIDDEN) {
+ nrBuilder.addForbiddenCapability(cap);
+ }
+ }
+
+ return nrBuilder.build();
}
/**
@@ -285,7 +365,6 @@
*/
private NetworkRequest.Builder getBaseNetworkRequestBuilder() {
return new NetworkRequest.Builder()
- .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
@@ -356,7 +435,7 @@
if (!allNetworkPriorities.isEmpty()) {
allNetworkPriorities += ", ";
}
- allNetworkPriorities += record.network + ": " + record.getPriorityClass();
+ allNetworkPriorities += record.network + ": " + record.priorityClass;
}
logInfo(
"Selected network changed to "
@@ -393,19 +472,22 @@
private TreeSet<UnderlyingNetworkRecord> getSortedUnderlyingNetworks() {
TreeSet<UnderlyingNetworkRecord> sorted =
- new TreeSet<>(
- UnderlyingNetworkRecord.getComparator(
+ new TreeSet<>(UnderlyingNetworkRecord.getComparator());
+
+ for (UnderlyingNetworkRecord.Builder builder :
+ mUnderlyingNetworkRecordBuilders.values()) {
+ if (builder.isValid()) {
+ final UnderlyingNetworkRecord record =
+ builder.build(
mVcnContext,
mConnectionConfig.getVcnUnderlyingNetworkPriorities(),
mSubscriptionGroup,
mLastSnapshot,
mCurrentRecord,
- mCarrierConfig));
-
- for (UnderlyingNetworkRecord.Builder builder :
- mUnderlyingNetworkRecordBuilders.values()) {
- if (builder.isValid()) {
- sorted.add(builder.build());
+ mCarrierConfig);
+ if (record.priorityClass != NetworkPriorityClassifier.PRIORITY_INVALID) {
+ sorted.add(record);
+ }
}
}
diff --git a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java
index 319680e..aea9f4d 100644
--- a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java
+++ b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java
@@ -42,53 +42,58 @@
* @hide
*/
public class UnderlyingNetworkRecord {
- private static final int PRIORITY_CLASS_INVALID = Integer.MAX_VALUE;
-
@NonNull public final Network network;
@NonNull public final NetworkCapabilities networkCapabilities;
@NonNull public final LinkProperties linkProperties;
public final boolean isBlocked;
-
- private int mPriorityClass = PRIORITY_CLASS_INVALID;
+ public final boolean isSelected;
+ public final int priorityClass;
@VisibleForTesting(visibility = Visibility.PRIVATE)
public UnderlyingNetworkRecord(
@NonNull Network network,
@NonNull NetworkCapabilities networkCapabilities,
@NonNull LinkProperties linkProperties,
- boolean isBlocked) {
- this.network = network;
- this.networkCapabilities = networkCapabilities;
- this.linkProperties = linkProperties;
- this.isBlocked = isBlocked;
- }
-
- private int getOrCalculatePriorityClass(
+ boolean isBlocked,
VcnContext vcnContext,
List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates,
ParcelUuid subscriptionGroup,
TelephonySubscriptionSnapshot snapshot,
UnderlyingNetworkRecord currentlySelected,
PersistableBundleWrapper carrierConfig) {
- // Never changes after the underlying network record is created.
- if (mPriorityClass == PRIORITY_CLASS_INVALID) {
- mPriorityClass =
- NetworkPriorityClassifier.calculatePriorityClass(
- vcnContext,
- this,
- underlyingNetworkTemplates,
- subscriptionGroup,
- snapshot,
- currentlySelected,
- carrierConfig);
- }
+ this.network = network;
+ this.networkCapabilities = networkCapabilities;
+ this.linkProperties = linkProperties;
+ this.isBlocked = isBlocked;
- return mPriorityClass;
+ this.isSelected = isSelected(this.network, currentlySelected);
+
+ priorityClass =
+ NetworkPriorityClassifier.calculatePriorityClass(
+ vcnContext,
+ this,
+ underlyingNetworkTemplates,
+ subscriptionGroup,
+ snapshot,
+ currentlySelected,
+ carrierConfig);
}
- // Used in UnderlyingNetworkController
- int getPriorityClass() {
- return mPriorityClass;
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public UnderlyingNetworkRecord(
+ @NonNull Network network,
+ @NonNull NetworkCapabilities networkCapabilities,
+ @NonNull LinkProperties linkProperties,
+ boolean isBlocked,
+ boolean isSelected,
+ int priorityClass) {
+ this.network = network;
+ this.networkCapabilities = networkCapabilities;
+ this.linkProperties = linkProperties;
+ this.isBlocked = isBlocked;
+ this.isSelected = isSelected;
+
+ this.priorityClass = priorityClass;
}
@Override
@@ -108,40 +113,32 @@
return Objects.hash(network, networkCapabilities, linkProperties, isBlocked);
}
- static Comparator<UnderlyingNetworkRecord> getComparator(
- VcnContext vcnContext,
- List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates,
- ParcelUuid subscriptionGroup,
- TelephonySubscriptionSnapshot snapshot,
- UnderlyingNetworkRecord currentlySelected,
- PersistableBundleWrapper carrierConfig) {
+ /** Returns if two records are equal including their priority classes. */
+ public static boolean isEqualIncludingPriorities(
+ UnderlyingNetworkRecord left, UnderlyingNetworkRecord right) {
+ if (left != null && right != null) {
+ return left.equals(right)
+ && left.isSelected == right.isSelected
+ && left.priorityClass == right.priorityClass;
+ }
+
+ return left == right;
+ }
+
+ static Comparator<UnderlyingNetworkRecord> getComparator() {
return (left, right) -> {
- final int leftIndex =
- left.getOrCalculatePriorityClass(
- vcnContext,
- underlyingNetworkTemplates,
- subscriptionGroup,
- snapshot,
- currentlySelected,
- carrierConfig);
- final int rightIndex =
- right.getOrCalculatePriorityClass(
- vcnContext,
- underlyingNetworkTemplates,
- subscriptionGroup,
- snapshot,
- currentlySelected,
- carrierConfig);
+ final int leftIndex = left.priorityClass;
+ final int rightIndex = right.priorityClass;
// In the case of networks in the same priority class, prioritize based on other
// criteria (eg. actively selected network, link metrics, etc)
if (leftIndex == rightIndex) {
// TODO: Improve the strategy of network selection when both UnderlyingNetworkRecord
// fall into the same priority class.
- if (isSelected(left, currentlySelected)) {
+ if (left.isSelected) {
return -1;
}
- if (isSelected(left, currentlySelected)) {
+ if (right.isSelected) {
return 1;
}
}
@@ -150,11 +147,11 @@
}
private static boolean isSelected(
- UnderlyingNetworkRecord recordToCheck, UnderlyingNetworkRecord currentlySelected) {
+ Network networkToCheck, UnderlyingNetworkRecord currentlySelected) {
if (currentlySelected == null) {
return false;
}
- if (currentlySelected.network == recordToCheck.network) {
+ if (currentlySelected.network.equals(networkToCheck)) {
return true;
}
return false;
@@ -172,16 +169,8 @@
pw.println("UnderlyingNetworkRecord:");
pw.increaseIndent();
- final int priorityIndex =
- getOrCalculatePriorityClass(
- vcnContext,
- underlyingNetworkTemplates,
- subscriptionGroup,
- snapshot,
- currentlySelected,
- carrierConfig);
-
- pw.println("Priority index: " + priorityIndex);
+ pw.println("priorityClass: " + priorityClass);
+ pw.println("isSelected: " + isSelected);
pw.println("mNetwork: " + network);
pw.println("mNetworkCapabilities: " + networkCapabilities);
pw.println("mLinkProperties: " + linkProperties);
@@ -198,8 +187,6 @@
boolean mIsBlocked;
boolean mWasIsBlockedSet;
- @Nullable private UnderlyingNetworkRecord mCached;
-
Builder(@NonNull Network network) {
mNetwork = network;
}
@@ -211,7 +198,6 @@
void setNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) {
mNetworkCapabilities = networkCapabilities;
- mCached = null;
}
@Nullable
@@ -221,32 +207,40 @@
void setLinkProperties(@NonNull LinkProperties linkProperties) {
mLinkProperties = linkProperties;
- mCached = null;
}
void setIsBlocked(boolean isBlocked) {
mIsBlocked = isBlocked;
mWasIsBlockedSet = true;
- mCached = null;
}
boolean isValid() {
return mNetworkCapabilities != null && mLinkProperties != null && mWasIsBlockedSet;
}
- UnderlyingNetworkRecord build() {
+ UnderlyingNetworkRecord build(
+ VcnContext vcnContext,
+ List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates,
+ ParcelUuid subscriptionGroup,
+ TelephonySubscriptionSnapshot snapshot,
+ UnderlyingNetworkRecord currentlySelected,
+ PersistableBundleWrapper carrierConfig) {
if (!isValid()) {
throw new IllegalArgumentException(
"Called build before UnderlyingNetworkRecord was valid");
}
- if (mCached == null) {
- mCached =
- new UnderlyingNetworkRecord(
- mNetwork, mNetworkCapabilities, mLinkProperties, mIsBlocked);
- }
-
- return mCached;
+ return new UnderlyingNetworkRecord(
+ mNetwork,
+ mNetworkCapabilities,
+ mLinkProperties,
+ mIsBlocked,
+ vcnContext,
+ underlyingNetworkTemplates,
+ subscriptionGroup,
+ snapshot,
+ currentlySelected,
+ carrierConfig);
}
}
}
diff --git a/services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java b/services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java
index d22ec0a..d6761a2 100644
--- a/services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java
+++ b/services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java
@@ -573,5 +573,10 @@
return isEqual(mBundle, other.mBundle);
}
+
+ @Override
+ public String toString() {
+ return mBundle.toString();
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 202fe55..2b15a79 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -63,6 +63,7 @@
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
@@ -261,7 +262,7 @@
boolean isSysUiPackage = info.packageName.equals(
mAtm.getSysUiServiceComponentLocked().getPackageName());
- if (isSysUiPackage || mUid == Process.SYSTEM_UID) {
+ if (isSysUiPackage || UserHandle.getAppId(mUid) == Process.SYSTEM_UID) {
// This is a system owned process and should not use an activity config.
// TODO(b/151161907): Remove after support for display-independent (raw) SysUi configs.
mIsActivityConfigOverrideAllowed = false;
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 87f45010..12d1bc3 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -39,7 +39,6 @@
import android.telecom.TelecomManager;
import android.telephony.AccessNetworkConstants.AccessNetworkType;
import android.telephony.data.ApnSetting;
-import android.telephony.data.DataCallResponse;
import android.telephony.gba.TlsParams;
import android.telephony.gba.UaSecurityProtocolIdentifier;
import android.telephony.ims.ImsReasonInfo;
@@ -1137,27 +1136,6 @@
public static final String KEY_DEFAULT_MTU_INT = "default_mtu_int";
/**
- * The data call retry configuration for different types of APN.
- * @hide
- */
- public static final String KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS =
- "carrier_data_call_retry_config_strings";
-
- /**
- * Delay in milliseconds between trying APN from the pool
- * @hide
- */
- public static final String KEY_CARRIER_DATA_CALL_APN_DELAY_DEFAULT_LONG =
- "carrier_data_call_apn_delay_default_long";
-
- /**
- * Faster delay in milliseconds between trying APN from the pool
- * @hide
- */
- public static final String KEY_CARRIER_DATA_CALL_APN_DELAY_FASTER_LONG =
- "carrier_data_call_apn_delay_faster_long";
-
- /**
* Delay in milliseconds for retrying APN after disconnect
* @hide
*/
@@ -1165,25 +1143,7 @@
"carrier_data_call_apn_retry_after_disconnect_long";
/**
- * The maximum times for telephony to retry data setup on the same APN requested by
- * network through the data setup response retry timer
- * {@link DataCallResponse#getRetryDurationMillis()}. This is to prevent that network keeps
- * asking device to retry data setup forever and causes power consumption issue. For infinite
- * retring same APN, configure this as 2147483647 (i.e. {@link Integer#MAX_VALUE}).
- *
- * Note if network does not suggest any retry timer, frameworks uses the retry configuration
- * from {@link #KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS}, and the maximum retry times could
- * be configured there.
- * @hide
- */
- public static final String KEY_CARRIER_DATA_CALL_RETRY_NETWORK_REQUESTED_MAX_COUNT_INT =
- "carrier_data_call_retry_network_requested_max_count_int";
-
- /**
- * Data call setup permanent failure causes by the carrier.
- *
- * @deprecated This API key was added in mistake and is not used anymore by the telephony data
- * frameworks.
+ * Data call setup permanent failure causes by the carrier
*/
@Deprecated
public static final String KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS =
@@ -1203,19 +1163,6 @@
"carrier_metered_roaming_apn_types_strings";
/**
- * APN types that are not allowed on cellular
- * @hide
- */
- public static final String KEY_CARRIER_WWAN_DISALLOWED_APN_TYPES_STRING_ARRAY =
- "carrier_wwan_disallowed_apn_types_string_array";
-
- /**
- * APN types that are not allowed on IWLAN
- * @hide
- */
- public static final String KEY_CARRIER_WLAN_DISALLOWED_APN_TYPES_STRING_ARRAY =
- "carrier_wlan_disallowed_apn_types_string_array";
- /**
* CDMA carrier ERI (Enhanced Roaming Indicator) file name
* @hide
*/
@@ -8349,7 +8296,6 @@
* "1800000, maximum_retries=20" means for those capabilities, retry happens in 2.5s, 3s, 5s,
* 10s, 15s, 20s, 40s, 1m, 2m, 4m, 10m, 20m, 30m, 30m, 30m, until reaching 20 retries.
*
- * // TODO: remove KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS
* @hide
*/
public static final String KEY_TELEPHONY_DATA_SETUP_RETRY_RULES_STRING_ARRAY =
@@ -8756,27 +8702,13 @@
sDefaults.putBoolean(KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL, false);
sDefaults.putBoolean(KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL, false);
sDefaults.putInt(KEY_DEFAULT_MTU_INT, 1500);
- sDefaults.putStringArray(KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, new String[]{
- "default:default_randomization=2000,5000,10000,20000,40000,80000:5000,160000:5000,"
- + "320000:5000,640000:5000,1280000:5000,1800000:5000",
- "mms:default_randomization=2000,5000,10000,20000,40000,80000:5000,160000:5000,"
- + "320000:5000,640000:5000,1280000:5000,1800000:5000",
- "ims:max_retries=10, 5000, 5000, 5000",
- "others:max_retries=3, 5000, 5000, 5000"});
- sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_DELAY_DEFAULT_LONG, 20000);
- sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_DELAY_FASTER_LONG, 3000);
sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_RETRY_AFTER_DISCONNECT_LONG, 3000);
- sDefaults.putInt(KEY_CARRIER_DATA_CALL_RETRY_NETWORK_REQUESTED_MAX_COUNT_INT, 3);
sDefaults.putString(KEY_CARRIER_ERI_FILE_NAME_STRING, "eri.xml");
sDefaults.putInt(KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT, 7200);
sDefaults.putStringArray(KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{"default", "mms", "dun", "supl"});
sDefaults.putStringArray(KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS,
new String[]{"default", "mms", "dun", "supl"});
- sDefaults.putStringArray(KEY_CARRIER_WWAN_DISALLOWED_APN_TYPES_STRING_ARRAY,
- new String[]{""});
- sDefaults.putStringArray(KEY_CARRIER_WLAN_DISALLOWED_APN_TYPES_STRING_ARRAY,
- new String[]{""});
sDefaults.putIntArray(KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY,
new int[] {TelephonyManager.NETWORK_TYPE_CDMA, TelephonyManager.NETWORK_TYPE_1xRTT,
TelephonyManager.NETWORK_TYPE_EVDO_0, TelephonyManager.NETWORK_TYPE_EVDO_A,
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 0ce6b14..da1ffcd 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2510,9 +2510,6 @@
CellIdentity getLastKnownCellIdentity(int subId, String callingPackage,
String callingFeatureId);
- /** Check if telephony new data stack is enabled. */
- boolean isUsingNewDataStack();
-
/**
* @return true if the modem service is set successfully, false otherwise.
*/
diff --git a/tests/SurfaceControlViewHostTest/OWNERS b/tests/SurfaceControlViewHostTest/OWNERS
new file mode 100644
index 0000000..0862c05
--- /dev/null
+++ b/tests/SurfaceControlViewHostTest/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/wm/OWNERS
diff --git a/tests/vcn/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java b/tests/vcn/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java
index 1f6bb21..1569613 100644
--- a/tests/vcn/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java
@@ -32,7 +32,8 @@
private static final Set<String> ALLOWED_PLMN_IDS = new HashSet<>();
private static final Set<Integer> ALLOWED_CARRIER_IDS = new HashSet<>();
- private static VcnCellUnderlyingNetworkTemplate.Builder getTestNetworkTemplateBuilder() {
+ // Public for use in UnderlyingNetworkControllerTest
+ public static VcnCellUnderlyingNetworkTemplate.Builder getTestNetworkTemplateBuilder() {
return new VcnCellUnderlyingNetworkTemplate.Builder()
.setMetered(MATCH_FORBIDDEN)
.setMinUpstreamBandwidthKbps(
diff --git a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
index 4040888..1883c85 100644
--- a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
@@ -100,14 +100,20 @@
EXPOSED_CAPS);
}
- // Public for use in VcnGatewayConnectionTest
- public static VcnGatewayConnectionConfig buildTestConfig() {
+ // Public for use in UnderlyingNetworkControllerTest
+ public static VcnGatewayConnectionConfig buildTestConfig(
+ List<VcnUnderlyingNetworkTemplate> nwTemplates) {
final VcnGatewayConnectionConfig.Builder builder =
- newBuilder().setVcnUnderlyingNetworkPriorities(UNDERLYING_NETWORK_TEMPLATES);
+ newBuilder().setVcnUnderlyingNetworkPriorities(nwTemplates);
return buildTestConfigWithExposedCaps(builder, EXPOSED_CAPS);
}
+ // Public for use in VcnGatewayConnectionTest
+ public static VcnGatewayConnectionConfig buildTestConfig() {
+ return buildTestConfig(UNDERLYING_NETWORK_TEMPLATES);
+ }
+
private static VcnGatewayConnectionConfig.Builder newBuilder() {
// Append a unique identifier to the name prefix to guarantee that all created
// VcnGatewayConnectionConfigs have a unique name (required by VcnConfig).
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index 1c21a06..aad7a5e 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -59,6 +59,7 @@
import android.net.NetworkCapabilities;
import android.net.ipsec.ike.ChildSaProposal;
import android.net.ipsec.ike.IkeSessionConnectionInfo;
+import android.net.ipsec.ike.TunnelModeChildSessionParams;
import android.net.ipsec.ike.exceptions.IkeException;
import android.net.ipsec.ike.exceptions.IkeInternalException;
import android.net.ipsec.ike.exceptions.IkeProtocolException;
@@ -70,6 +71,7 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.vcn.VcnGatewayConnection.VcnChildSessionCallback;
import com.android.server.vcn.routeselection.UnderlyingNetworkRecord;
import com.android.server.vcn.util.MtuUtils;
@@ -90,6 +92,8 @@
@RunWith(AndroidJUnit4.class)
@SmallTest
public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnectionTestBase {
+ private static final int PARALLEL_SA_COUNT = 4;
+
private VcnIkeSession mIkeSession;
private VcnNetworkAgent mNetworkAgent;
private Network mVcnNetwork;
@@ -227,16 +231,29 @@
private void verifyVcnTransformsApplied(
VcnGatewayConnection vcnGatewayConnection, boolean expectForwardTransform)
throws Exception {
+ verifyVcnTransformsApplied(
+ vcnGatewayConnection,
+ expectForwardTransform,
+ Collections.singletonList(getChildSessionCallback()));
+ }
+
+ private void verifyVcnTransformsApplied(
+ VcnGatewayConnection vcnGatewayConnection,
+ boolean expectForwardTransform,
+ List<VcnChildSessionCallback> callbacks)
+ throws Exception {
for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT}) {
- getChildSessionCallback().onIpSecTransformCreated(makeDummyIpSecTransform(), direction);
+ for (VcnChildSessionCallback cb : callbacks) {
+ cb.onIpSecTransformCreated(makeDummyIpSecTransform(), direction);
+ }
mTestLooper.dispatchAll();
- verify(mIpSecSvc)
+ verify(mIpSecSvc, times(callbacks.size()))
.applyTunnelModeTransform(
eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(direction), anyInt(), any());
}
- verify(mIpSecSvc, expectForwardTransform ? times(1) : never())
+ verify(mIpSecSvc, expectForwardTransform ? times(callbacks.size()) : never())
.applyTunnelModeTransform(
eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(DIRECTION_FWD), anyInt(), any());
@@ -416,6 +433,89 @@
verifySafeModeStateAndCallbackFired(1 /* invocationCount */, false /* isInSafeMode */);
}
+ private List<VcnChildSessionCallback> openChildAndVerifyParallelSasRequested()
+ throws Exception {
+ doReturn(PARALLEL_SA_COUNT)
+ .when(mDeps)
+ .getParallelTunnelCount(eq(TEST_SUBSCRIPTION_SNAPSHOT), eq(TEST_SUB_GRP));
+
+ // Verify scheduled but not canceled when entering ConnectedState
+ verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+ triggerChildOpened();
+ mTestLooper.dispatchAll();
+
+ // Verify new child sessions requested
+ final ArgumentCaptor<VcnChildSessionCallback> captor =
+ ArgumentCaptor.forClass(VcnChildSessionCallback.class);
+ verify(mIkeSession, times(PARALLEL_SA_COUNT - 1))
+ .openChildSession(any(TunnelModeChildSessionParams.class), captor.capture());
+
+ return captor.getAllValues();
+ }
+
+ private List<VcnChildSessionCallback> verifyChildOpenedRequestsAndAppliesParallelSas()
+ throws Exception {
+ List<VcnChildSessionCallback> callbacks = openChildAndVerifyParallelSasRequested();
+
+ verifyVcnTransformsApplied(mGatewayConnection, false, callbacks);
+
+ // Mock IKE calling of onOpened()
+ for (VcnChildSessionCallback cb : callbacks) {
+ cb.onOpened(mock(VcnChildSessionConfiguration.class));
+ }
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
+ return callbacks;
+ }
+
+ @Test
+ public void testChildOpenedWithParallelSas() throws Exception {
+ verifyChildOpenedRequestsAndAppliesParallelSas();
+ }
+
+ @Test
+ public void testOpportunisticSa_ignoresPreOpenFailures() throws Exception {
+ List<VcnChildSessionCallback> callbacks = openChildAndVerifyParallelSasRequested();
+
+ for (VcnChildSessionCallback cb : callbacks) {
+ cb.onClosed();
+ cb.onClosedExceptionally(mock(IkeException.class));
+ }
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
+ assertEquals(mIkeConnectionInfo, mGatewayConnection.getIkeConnectionInfo());
+ }
+
+ private void verifyPostOpenFailuresCloseSession(boolean shouldCloseWithException)
+ throws Exception {
+ List<VcnChildSessionCallback> callbacks = verifyChildOpenedRequestsAndAppliesParallelSas();
+
+ for (VcnChildSessionCallback cb : callbacks) {
+ if (shouldCloseWithException) {
+ cb.onClosed();
+ } else {
+ cb.onClosedExceptionally(mock(IkeException.class));
+ }
+ }
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+ verify(mIkeSession).close();
+ }
+
+ @Test
+ public void testOpportunisticSa_handlesPostOpenFailures_onClosed() throws Exception {
+ verifyPostOpenFailuresCloseSession(false /* shouldCloseWithException */);
+ }
+
+ @Test
+ public void testOpportunisticSa_handlesPostOpenFailures_onClosedExceptionally()
+ throws Exception {
+ verifyPostOpenFailuresCloseSession(true /* shouldCloseWithException */);
+ }
+
@Test
public void testInternalAndDnsAddressesChanged() throws Exception {
final List<LinkAddress> startingInternalAddrs =
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
index a4ee2de..692c8a8 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
@@ -143,9 +143,9 @@
capBuilder.setLinkDownstreamBandwidthKbps(TEST_DOWNSTREAM_BANDWIDTH);
capBuilder.setAdministratorUids(new int[] {TEST_UID});
final Network underlyingNetwork = mock(Network.class, CALLS_REAL_METHODS);
- UnderlyingNetworkRecord record = new UnderlyingNetworkRecord(
- underlyingNetwork,
- capBuilder.build(), new LinkProperties(), false);
+ UnderlyingNetworkRecord record =
+ getTestNetworkRecord(
+ underlyingNetwork, capBuilder.build(), new LinkProperties(), false);
final NetworkCapabilities vcnCaps =
VcnGatewayConnection.buildNetworkCapabilities(
VcnGatewayConnectionConfigTest.buildTestConfig(),
@@ -211,7 +211,7 @@
doReturn(TEST_DNS_ADDRESSES).when(childSessionConfig).getInternalDnsServers();
UnderlyingNetworkRecord record =
- new UnderlyingNetworkRecord(
+ getTestNetworkRecord(
mock(Network.class, CALLS_REAL_METHODS),
new NetworkCapabilities.Builder().build(),
underlyingLp,
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
index 7bafd24..bb123ff 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -109,9 +109,23 @@
protected static final long ELAPSED_REAL_TIME = 123456789L;
protected static final String TEST_IPSEC_TUNNEL_IFACE = "IPSEC_IFACE";
+ protected static UnderlyingNetworkRecord getTestNetworkRecord(
+ Network network,
+ NetworkCapabilities networkCapabilities,
+ LinkProperties linkProperties,
+ boolean isBlocked) {
+ return new UnderlyingNetworkRecord(
+ network,
+ networkCapabilities,
+ linkProperties,
+ isBlocked,
+ false /* isSelected */,
+ 0 /* priorityClass */);
+ }
+
protected static final String TEST_TCP_BUFFER_SIZES_1 = "1,2,3,4";
protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 =
- new UnderlyingNetworkRecord(
+ getTestNetworkRecord(
mock(Network.class, CALLS_REAL_METHODS),
new NetworkCapabilities(),
new LinkProperties(),
@@ -124,7 +138,7 @@
protected static final String TEST_TCP_BUFFER_SIZES_2 = "2,3,4,5";
protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_2 =
- new UnderlyingNetworkRecord(
+ getTestNetworkRecord(
mock(Network.class, CALLS_REAL_METHODS),
new NetworkCapabilities(),
new LinkProperties(),
@@ -209,6 +223,9 @@
doReturn(mWakeLock)
.when(mDeps)
.newWakeLock(eq(mContext), eq(PowerManager.PARTIAL_WAKE_LOCK), any());
+ doReturn(1)
+ .when(mDeps)
+ .getParallelTunnelCount(eq(TEST_SUBSCRIPTION_SNAPSHOT), eq(TEST_SUB_GRP));
setUpWakeupMessage(mTeardownTimeoutAlarm, VcnGatewayConnection.TEARDOWN_TIMEOUT_ALARM);
setUpWakeupMessage(mDisconnectRequestAlarm, VcnGatewayConnection.DISCONNECT_REQUEST_ALARM);
diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java
index b0d6895..629e988 100644
--- a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java
@@ -16,6 +16,7 @@
package com.android.server.vcn.routeselection;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN;
import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED;
import static android.net.vcn.VcnUnderlyingNetworkTemplateTestBase.TEST_MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS;
@@ -24,8 +25,8 @@
import static android.net.vcn.VcnUnderlyingNetworkTemplateTestBase.TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS;
import static com.android.server.vcn.VcnTestUtils.setupSystemService;
-import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.PRIORITY_ANY;
-import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.calculatePriorityClass;
+import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.PRIORITY_FALLBACK;
+import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.PRIORITY_INVALID;
import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesCellPriorityRule;
import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesPriorityRule;
import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesWifiPriorityRule;
@@ -48,6 +49,7 @@
import android.net.vcn.VcnCellUnderlyingNetworkTemplate;
import android.net.vcn.VcnGatewayConnectionConfig;
import android.net.vcn.VcnManager;
+import android.net.vcn.VcnUnderlyingNetworkTemplate;
import android.net.vcn.VcnWifiUnderlyingNetworkTemplate;
import android.os.ParcelUuid;
import android.os.PersistableBundle;
@@ -64,6 +66,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Collections;
+import java.util.List;
import java.util.Set;
import java.util.UUID;
@@ -102,6 +106,7 @@
private static final NetworkCapabilities CELL_NETWORK_CAPABILITIES =
new NetworkCapabilities.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN)
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.setSubscriptionIds(Set.of(SUB_ID))
.setNetworkSpecifier(TEL_NETWORK_SPECIFIER)
@@ -135,25 +140,35 @@
false /* isInTestMode */));
doNothing().when(mVcnContext).ensureRunningOnLooperThread();
- mWifiNetworkRecord =
- new UnderlyingNetworkRecord(
- mNetwork,
- WIFI_NETWORK_CAPABILITIES,
- LINK_PROPERTIES,
- false /* isBlocked */);
-
- mCellNetworkRecord =
- new UnderlyingNetworkRecord(
- mNetwork,
- CELL_NETWORK_CAPABILITIES,
- LINK_PROPERTIES,
- false /* isBlocked */);
-
setupSystemService(
mockContext, mTelephonyManager, Context.TELEPHONY_SERVICE, TelephonyManager.class);
when(mTelephonyManager.createForSubscriptionId(SUB_ID)).thenReturn(mTelephonyManager);
when(mTelephonyManager.getNetworkOperator()).thenReturn(PLMN_ID);
when(mTelephonyManager.getSimSpecificCarrierId()).thenReturn(CARRIER_ID);
+
+ mWifiNetworkRecord =
+ getTestNetworkRecord(
+ WIFI_NETWORK_CAPABILITIES,
+ VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES);
+ mCellNetworkRecord =
+ getTestNetworkRecord(
+ CELL_NETWORK_CAPABILITIES,
+ VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES);
+ }
+
+ private UnderlyingNetworkRecord getTestNetworkRecord(
+ NetworkCapabilities nc, List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates) {
+ return new UnderlyingNetworkRecord(
+ mNetwork,
+ nc,
+ LINK_PROPERTIES,
+ false /* isBlocked */,
+ mVcnContext,
+ underlyingNetworkTemplates,
+ SUB_GROUP,
+ mSubscriptionSnapshot,
+ null /* currentlySelected */,
+ null /* carrierConfig */);
}
@Test
@@ -490,37 +505,72 @@
mSubscriptionSnapshot));
}
- private void verifyCalculatePriorityClass(
- UnderlyingNetworkRecord networkRecord, int expectedIndex) {
- final int priorityIndex =
- calculatePriorityClass(
+ private void verifyMatchCellWithRequiredCapabilities(
+ VcnCellUnderlyingNetworkTemplate template, boolean expectMatch) {
+ assertEquals(
+ expectMatch,
+ checkMatchesCellPriorityRule(
mVcnContext,
- networkRecord,
- VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES,
+ template,
+ mCellNetworkRecord,
SUB_GROUP,
- mSubscriptionSnapshot,
- null /* currentlySelected */,
- null /* carrierConfig */);
+ mSubscriptionSnapshot));
+ }
- assertEquals(expectedIndex, priorityIndex);
+ @Test
+ public void testMatchCell() {
+ final VcnCellUnderlyingNetworkTemplate template =
+ getCellNetworkPriorityBuilder().setInternet(MATCH_REQUIRED).build();
+ verifyMatchCellWithRequiredCapabilities(template, true /* expectMatch */);
+ }
+
+ @Test
+ public void testMatchCellFail_RequiredCapabilitiesMissing() {
+ final VcnCellUnderlyingNetworkTemplate template =
+ getCellNetworkPriorityBuilder().setCbs(MATCH_REQUIRED).build();
+ verifyMatchCellWithRequiredCapabilities(template, false /* expectMatch */);
+ }
+
+ @Test
+ public void testMatchCellFail_ForbiddenCapabilitiesFound() {
+ final VcnCellUnderlyingNetworkTemplate template =
+ getCellNetworkPriorityBuilder().setDun(MATCH_FORBIDDEN).build();
+ verifyMatchCellWithRequiredCapabilities(template, false /* expectMatch */);
}
@Test
public void testCalculatePriorityClass() throws Exception {
- verifyCalculatePriorityClass(mCellNetworkRecord, 2);
+ assertEquals(2, mCellNetworkRecord.priorityClass);
+ }
+
+ private void checkCalculatePriorityClassFailToMatchAny(
+ boolean hasInternet, int expectedPriorityClass) throws Exception {
+ final List<VcnUnderlyingNetworkTemplate> templatesRequireDun =
+ Collections.singletonList(
+ new VcnCellUnderlyingNetworkTemplate.Builder()
+ .setDun(MATCH_REQUIRED)
+ .build());
+
+ final NetworkCapabilities.Builder ncBuilder =
+ new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+ if (hasInternet) {
+ ncBuilder.addCapability(NET_CAPABILITY_INTERNET);
+ }
+
+ final UnderlyingNetworkRecord nonDunNetworkRecord =
+ getTestNetworkRecord(ncBuilder.build(), templatesRequireDun);
+
+ assertEquals(expectedPriorityClass, nonDunNetworkRecord.priorityClass);
}
@Test
- public void testCalculatePriorityClassFailToMatchAny() throws Exception {
- final NetworkCapabilities nc =
- new NetworkCapabilities.Builder()
- .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
- .setSignalStrength(WIFI_RSSI_LOW)
- .setSsid(SSID)
- .build();
- final UnderlyingNetworkRecord wifiNetworkRecord =
- new UnderlyingNetworkRecord(mNetwork, nc, LINK_PROPERTIES, false /* isBlocked */);
+ public void testCalculatePriorityClassFailToMatchAny_InternetNetwork() throws Exception {
+ checkCalculatePriorityClassFailToMatchAny(true /* hasInternet */, PRIORITY_FALLBACK);
+ }
- verifyCalculatePriorityClass(wifiNetworkRecord, PRIORITY_ANY);
+ @Test
+ public void testCalculatePriorityClassFailToMatchAny_NonInternetNetwork() throws Exception {
+ checkCalculatePriorityClassFailToMatchAny(false /* hasInternet */, PRIORITY_INVALID);
}
}
diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java
index fad9669..2941fde 100644
--- a/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java
@@ -16,18 +16,29 @@
package com.android.server.vcn.routeselection;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
+import static android.net.vcn.VcnCellUnderlyingNetworkTemplate.MATCH_ANY;
+import static android.net.vcn.VcnCellUnderlyingNetworkTemplate.MATCH_FORBIDDEN;
+import static android.net.vcn.VcnCellUnderlyingNetworkTemplate.MATCH_REQUIRED;
+
import static com.android.server.vcn.VcnTestUtils.setupSystemService;
import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT;
import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.WIFI_EXIT_RSSI_THRESHOLD_DEFAULT;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
@@ -42,7 +53,10 @@
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.TelephonyNetworkSpecifier;
+import android.net.vcn.VcnCellUnderlyingNetworkTemplate;
+import android.net.vcn.VcnCellUnderlyingNetworkTemplateTest;
import android.net.vcn.VcnGatewayConnectionConfigTest;
+import android.net.vcn.VcnUnderlyingNetworkTemplate;
import android.os.ParcelUuid;
import android.os.test.TestLooper;
import android.telephony.CarrierConfigManager;
@@ -64,7 +78,10 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
import java.util.Set;
import java.util.UUID;
@@ -95,11 +112,39 @@
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.build();
+ private static final NetworkCapabilities DUN_NETWORK_CAPABILITIES =
+ new NetworkCapabilities.Builder()
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
+ .build();
+
+ private static final NetworkCapabilities CBS_NETWORK_CAPABILITIES =
+ new NetworkCapabilities.Builder()
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_CBS)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
+ .build();
+
private static final LinkProperties INITIAL_LINK_PROPERTIES =
getLinkPropertiesWithName("initial_iface");
private static final LinkProperties UPDATED_LINK_PROPERTIES =
getLinkPropertiesWithName("updated_iface");
+ private static final VcnCellUnderlyingNetworkTemplate CELL_TEMPLATE_DUN =
+ new VcnCellUnderlyingNetworkTemplate.Builder()
+ .setInternet(MATCH_ANY)
+ .setDun(MATCH_REQUIRED)
+ .build();
+
+ private static final VcnCellUnderlyingNetworkTemplate CELL_TEMPLATE_CBS =
+ new VcnCellUnderlyingNetworkTemplate.Builder()
+ .setInternet(MATCH_ANY)
+ .setCbs(MATCH_REQUIRED)
+ .build();
+
@Mock private Context mContext;
@Mock private VcnNetworkProvider mVcnNetworkProvider;
@Mock private ConnectivityManager mConnectivityManager;
@@ -201,6 +246,107 @@
any());
}
+ private void verifyRequestBackgroundNetwork(
+ ConnectivityManager cm,
+ int expectedSubId,
+ Set<Integer> expectedRequiredCaps,
+ Set<Integer> expectedForbiddenCaps) {
+ verify(cm)
+ .requestBackgroundNetwork(
+ eq(
+ getCellRequestForSubId(
+ expectedSubId,
+ expectedRequiredCaps,
+ expectedForbiddenCaps)),
+ any(NetworkBringupCallback.class),
+ any());
+ }
+
+ @Test
+ public void testNetworkCallbacksRegisteredOnStartupForNonInternetCapabilities() {
+ final ConnectivityManager cm = mock(ConnectivityManager.class);
+ setupSystemService(mContext, cm, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
+
+ // Build network templates
+ final List<VcnUnderlyingNetworkTemplate> networkTemplates = new ArrayList();
+
+ networkTemplates.add(
+ VcnCellUnderlyingNetworkTemplateTest.getTestNetworkTemplateBuilder()
+ .setDun(MATCH_REQUIRED)
+ .setInternet(MATCH_ANY)
+ .build());
+
+ networkTemplates.add(
+ VcnCellUnderlyingNetworkTemplateTest.getTestNetworkTemplateBuilder()
+ .setMms(MATCH_REQUIRED)
+ .setCbs(MATCH_FORBIDDEN)
+ .setInternet(MATCH_ANY)
+ .build());
+
+ // Start UnderlyingNetworkController
+ new UnderlyingNetworkController(
+ mVcnContext,
+ VcnGatewayConnectionConfigTest.buildTestConfig(networkTemplates),
+ SUB_GROUP,
+ mSubscriptionSnapshot,
+ mNetworkControllerCb);
+
+ // Verifications
+ for (final int subId : INITIAL_SUB_IDS) {
+ verifyRequestBackgroundNetwork(
+ cm,
+ subId,
+ Collections.singleton(NET_CAPABILITY_INTERNET),
+ Collections.emptySet());
+ verifyRequestBackgroundNetwork(
+ cm, subId, Collections.singleton(NET_CAPABILITY_DUN), Collections.emptySet());
+ verifyRequestBackgroundNetwork(
+ cm,
+ subId,
+ Collections.singleton(NET_CAPABILITY_MMS),
+ Collections.singleton(NET_CAPABILITY_CBS));
+ }
+ }
+
+ @Test
+ public void testNetworkCallbacksRegisteredOnStartupWithDedupedtCapabilities() {
+ final ConnectivityManager cm = mock(ConnectivityManager.class);
+ setupSystemService(mContext, cm, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
+
+ // Build network templates
+ final List<VcnUnderlyingNetworkTemplate> networkTemplates = new ArrayList();
+ final VcnCellUnderlyingNetworkTemplate.Builder builder =
+ new VcnCellUnderlyingNetworkTemplate.Builder()
+ .setMms(MATCH_REQUIRED)
+ .setCbs(MATCH_FORBIDDEN)
+ .setInternet(MATCH_ANY);
+
+ networkTemplates.add(builder.setMetered(MATCH_REQUIRED).build());
+ networkTemplates.add(builder.setMetered(MATCH_FORBIDDEN).build());
+
+ // Start UnderlyingNetworkController
+ new UnderlyingNetworkController(
+ mVcnContext,
+ VcnGatewayConnectionConfigTest.buildTestConfig(networkTemplates),
+ SUB_GROUP,
+ mSubscriptionSnapshot,
+ mNetworkControllerCb);
+
+ // Verifications
+ for (final int subId : INITIAL_SUB_IDS) {
+ verifyRequestBackgroundNetwork(
+ cm,
+ subId,
+ Collections.singleton(NET_CAPABILITY_INTERNET),
+ Collections.emptySet());
+ verifyRequestBackgroundNetwork(
+ cm,
+ subId,
+ Collections.singleton(NET_CAPABILITY_MMS),
+ Collections.singleton(NET_CAPABILITY_CBS));
+ }
+ }
+
private void verifyNetworkRequestsRegistered(Set<Integer> expectedSubIds) {
verify(mConnectivityManager)
.requestBackgroundNetwork(
@@ -210,8 +356,13 @@
for (final int subId : expectedSubIds) {
verify(mConnectivityManager)
.requestBackgroundNetwork(
- eq(getCellRequestForSubId(subId)),
- any(NetworkBringupCallback.class), any());
+ eq(
+ getCellRequestForSubId(
+ subId,
+ Collections.singleton(NET_CAPABILITY_INTERNET),
+ Collections.emptySet())),
+ any(NetworkBringupCallback.class),
+ any());
}
verify(mConnectivityManager)
@@ -253,6 +404,7 @@
private NetworkRequest getWifiRequest(Set<Integer> netCapsSubIds) {
return getExpectedRequestBase()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.setSubscriptionIds(netCapsSubIds)
.build();
}
@@ -261,6 +413,7 @@
// TODO (b/187991063): Add tests for carrier-config based thresholds
return getExpectedRequestBase()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.setSubscriptionIds(netCapsSubIds)
.setSignalStrength(WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT)
.build();
@@ -270,16 +423,27 @@
// TODO (b/187991063): Add tests for carrier-config based thresholds
return getExpectedRequestBase()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.setSubscriptionIds(netCapsSubIds)
.setSignalStrength(WIFI_EXIT_RSSI_THRESHOLD_DEFAULT)
.build();
}
- private NetworkRequest getCellRequestForSubId(int subId) {
- return getExpectedRequestBase()
- .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
- .setNetworkSpecifier(new TelephonyNetworkSpecifier(subId))
- .build();
+ private NetworkRequest getCellRequestForSubId(
+ int subId, Set<Integer> requiredCaps, Set<Integer> forbiddenCaps) {
+ final NetworkRequest.Builder nqBuilder =
+ getExpectedRequestBase()
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .setNetworkSpecifier(new TelephonyNetworkSpecifier(subId));
+
+ for (int cap : requiredCaps) {
+ nqBuilder.addCapability(cap);
+ }
+ for (int cap : forbiddenCaps) {
+ nqBuilder.addForbiddenCapability(cap);
+ }
+
+ return nqBuilder.build();
}
private NetworkRequest getRouteSelectionRequest(Set<Integer> netCapsSubIds) {
@@ -301,7 +465,6 @@
private NetworkRequest.Builder getExpectedRequestBase() {
final NetworkRequest.Builder builder =
new NetworkRequest.Builder()
- .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
@@ -321,16 +484,30 @@
.unregisterNetworkCallback(any(UnderlyingNetworkListener.class));
}
+ private static UnderlyingNetworkRecord getTestNetworkRecord(
+ Network network,
+ NetworkCapabilities networkCapabilities,
+ LinkProperties linkProperties,
+ boolean isBlocked) {
+ return new UnderlyingNetworkRecord(
+ network,
+ networkCapabilities,
+ linkProperties,
+ isBlocked,
+ false /* isSelected */,
+ 0 /* priorityClass */);
+ }
+
@Test
public void testUnderlyingNetworkRecordEquals() {
UnderlyingNetworkRecord recordA =
- new UnderlyingNetworkRecord(
+ getTestNetworkRecord(
mNetwork,
INITIAL_NETWORK_CAPABILITIES,
INITIAL_LINK_PROPERTIES,
false /* isBlocked */);
UnderlyingNetworkRecord recordB =
- new UnderlyingNetworkRecord(
+ getTestNetworkRecord(
mNetwork,
INITIAL_NETWORK_CAPABILITIES,
INITIAL_LINK_PROPERTIES,
@@ -338,12 +515,24 @@
UnderlyingNetworkRecord recordC =
new UnderlyingNetworkRecord(
mNetwork,
+ INITIAL_NETWORK_CAPABILITIES,
+ INITIAL_LINK_PROPERTIES,
+ false /* isBlocked */,
+ true /* isSelected */,
+ -1 /* priorityClass */);
+ UnderlyingNetworkRecord recordD =
+ getTestNetworkRecord(
+ mNetwork,
UPDATED_NETWORK_CAPABILITIES,
UPDATED_LINK_PROPERTIES,
false /* isBlocked */);
assertEquals(recordA, recordB);
- assertNotEquals(recordA, recordC);
+ assertEquals(recordA, recordC);
+ assertNotEquals(recordA, recordD);
+
+ assertTrue(UnderlyingNetworkRecord.isEqualIncludingPriorities(recordA, recordB));
+ assertFalse(UnderlyingNetworkRecord.isEqualIncludingPriorities(recordA, recordC));
}
@Test
@@ -366,6 +555,10 @@
.build();
}
+ private void verifyOnSelectedUnderlyingNetworkChanged(UnderlyingNetworkRecord expectedRecord) {
+ verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ }
+
private UnderlyingNetworkListener verifyRegistrationOnAvailableAndGetCallback(
NetworkCapabilities networkCapabilities) {
verify(mConnectivityManager)
@@ -384,12 +577,12 @@
cb.onBlockedStatusChanged(mNetwork, false /* isFalse */);
UnderlyingNetworkRecord expectedRecord =
- new UnderlyingNetworkRecord(
+ getTestNetworkRecord(
mNetwork,
responseNetworkCaps,
INITIAL_LINK_PROPERTIES,
false /* isBlocked */);
- verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ verifyOnSelectedUnderlyingNetworkChanged(expectedRecord);
return cb;
}
@@ -402,12 +595,12 @@
cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps);
UnderlyingNetworkRecord expectedRecord =
- new UnderlyingNetworkRecord(
+ getTestNetworkRecord(
mNetwork,
responseNetworkCaps,
INITIAL_LINK_PROPERTIES,
false /* isBlocked */);
- verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ verifyOnSelectedUnderlyingNetworkChanged(expectedRecord);
}
@Test
@@ -417,12 +610,12 @@
cb.onLinkPropertiesChanged(mNetwork, UPDATED_LINK_PROPERTIES);
UnderlyingNetworkRecord expectedRecord =
- new UnderlyingNetworkRecord(
+ getTestNetworkRecord(
mNetwork,
buildResponseNwCaps(INITIAL_NETWORK_CAPABILITIES, INITIAL_SUB_IDS),
UPDATED_LINK_PROPERTIES,
false /* isBlocked */);
- verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ verifyOnSelectedUnderlyingNetworkChanged(expectedRecord);
}
@Test
@@ -434,18 +627,16 @@
cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps);
UnderlyingNetworkRecord expectedRecord =
- new UnderlyingNetworkRecord(
+ getTestNetworkRecord(
mNetwork,
responseNetworkCaps,
INITIAL_LINK_PROPERTIES,
false /* isBlocked */);
- verify(mNetworkControllerCb, times(1))
- .onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ verifyOnSelectedUnderlyingNetworkChanged(expectedRecord);
// onSelectedUnderlyingNetworkChanged() won't be fired twice if network capabilities doesn't
// change.
cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps);
- verify(mNetworkControllerCb, times(1))
- .onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ verifyOnSelectedUnderlyingNetworkChanged(expectedRecord);
}
@Test
@@ -458,18 +649,16 @@
cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps);
UnderlyingNetworkRecord expectedRecord =
- new UnderlyingNetworkRecord(
+ getTestNetworkRecord(
mNetwork,
responseNetworkCaps,
INITIAL_LINK_PROPERTIES,
false /* isBlocked */);
- verify(mNetworkControllerCb, times(1))
- .onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ verifyOnSelectedUnderlyingNetworkChanged(expectedRecord);
// onSelectedUnderlyingNetworkChanged() won't be fired twice if network capabilities doesn't
// change.
cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps);
- verify(mNetworkControllerCb, times(1))
- .onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ verifyOnSelectedUnderlyingNetworkChanged(expectedRecord);
}
@Test
@@ -478,13 +667,7 @@
cb.onBlockedStatusChanged(mNetwork, true /* isBlocked */);
- UnderlyingNetworkRecord expectedRecord =
- new UnderlyingNetworkRecord(
- mNetwork,
- buildResponseNwCaps(INITIAL_NETWORK_CAPABILITIES, INITIAL_SUB_IDS),
- INITIAL_LINK_PROPERTIES,
- true /* isBlocked */);
- verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ verifyOnSelectedUnderlyingNetworkChanged(null);
}
@Test
@@ -520,5 +703,132 @@
verify(mNetworkControllerCb, times(1)).onSelectedUnderlyingNetworkChanged(any());
}
- // TODO (b/187991063): Add tests for network prioritization
+ private UnderlyingNetworkListener setupControllerAndGetNetworkListener(
+ List<VcnUnderlyingNetworkTemplate> networkTemplates) {
+ final ConnectivityManager cm = mock(ConnectivityManager.class);
+ setupSystemService(mContext, cm, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
+
+ new UnderlyingNetworkController(
+ mVcnContext,
+ VcnGatewayConnectionConfigTest.buildTestConfig(networkTemplates),
+ SUB_GROUP,
+ mSubscriptionSnapshot,
+ mNetworkControllerCb);
+
+ verify(cm)
+ .registerNetworkCallback(
+ eq(getRouteSelectionRequest(INITIAL_SUB_IDS)),
+ mUnderlyingNetworkListenerCaptor.capture(),
+ any());
+
+ return mUnderlyingNetworkListenerCaptor.getValue();
+ }
+
+ private UnderlyingNetworkRecord bringupNetworkAndGetRecord(
+ UnderlyingNetworkListener cb,
+ NetworkCapabilities requestNetworkCaps,
+ List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates,
+ UnderlyingNetworkRecord currentlySelected) {
+ final Network network = mock(Network.class);
+ final NetworkCapabilities responseNetworkCaps =
+ buildResponseNwCaps(requestNetworkCaps, INITIAL_SUB_IDS);
+
+ cb.onAvailable(network);
+ cb.onCapabilitiesChanged(network, responseNetworkCaps);
+ cb.onLinkPropertiesChanged(network, INITIAL_LINK_PROPERTIES);
+ cb.onBlockedStatusChanged(network, false /* isFalse */);
+ return new UnderlyingNetworkRecord(
+ network,
+ responseNetworkCaps,
+ INITIAL_LINK_PROPERTIES,
+ false /* isBlocked */,
+ mVcnContext,
+ underlyingNetworkTemplates,
+ SUB_GROUP,
+ mSubscriptionSnapshot,
+ currentlySelected,
+ null /* carrierConfig */);
+ }
+
+ @Test
+ public void testSelectMorePreferredNetwork() {
+ final List<VcnUnderlyingNetworkTemplate> networkTemplates = new ArrayList();
+ networkTemplates.add(CELL_TEMPLATE_DUN);
+ networkTemplates.add(CELL_TEMPLATE_CBS);
+
+ UnderlyingNetworkListener cb = setupControllerAndGetNetworkListener(networkTemplates);
+
+ // Bring up CBS network
+ final UnderlyingNetworkRecord cbsNetworkRecord =
+ bringupNetworkAndGetRecord(
+ cb,
+ CBS_NETWORK_CAPABILITIES,
+ networkTemplates,
+ null /* currentlySelected */);
+ verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(cbsNetworkRecord));
+
+ // Bring up DUN network
+ final UnderlyingNetworkRecord dunNetworkRecord =
+ bringupNetworkAndGetRecord(
+ cb, DUN_NETWORK_CAPABILITIES, networkTemplates, cbsNetworkRecord);
+ verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(dunNetworkRecord));
+ }
+
+ @Test
+ public void testNeverSelectLessPreferredNetwork() {
+ final List<VcnUnderlyingNetworkTemplate> networkTemplates = new ArrayList();
+ networkTemplates.add(CELL_TEMPLATE_DUN);
+ networkTemplates.add(CELL_TEMPLATE_CBS);
+
+ UnderlyingNetworkListener cb = setupControllerAndGetNetworkListener(networkTemplates);
+
+ // Bring up DUN network
+ final UnderlyingNetworkRecord dunNetworkRecord =
+ bringupNetworkAndGetRecord(
+ cb,
+ DUN_NETWORK_CAPABILITIES,
+ networkTemplates,
+ null /* currentlySelected */);
+ verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(dunNetworkRecord));
+
+ // Bring up CBS network
+ final UnderlyingNetworkRecord cbsNetworkRecord =
+ bringupNetworkAndGetRecord(
+ cb, CBS_NETWORK_CAPABILITIES, networkTemplates, dunNetworkRecord);
+ verify(mNetworkControllerCb, never())
+ .onSelectedUnderlyingNetworkChanged(eq(cbsNetworkRecord));
+ }
+
+ @Test
+ public void testFailtoMatchTemplateAndFallBackToInternetNetwork() {
+ final List<VcnUnderlyingNetworkTemplate> networkTemplates = new ArrayList();
+
+ networkTemplates.add(
+ new VcnCellUnderlyingNetworkTemplate.Builder().setDun(MATCH_REQUIRED).build());
+ UnderlyingNetworkListener cb = setupControllerAndGetNetworkListener(networkTemplates);
+
+ // Bring up an Internet network without DUN capability
+ final UnderlyingNetworkRecord networkRecord =
+ bringupNetworkAndGetRecord(
+ cb,
+ INITIAL_NETWORK_CAPABILITIES,
+ networkTemplates,
+ null /* currentlySelected */);
+ verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(networkRecord));
+ }
+
+ @Test
+ public void testFailtoMatchTemplateAndNeverFallBackToNonInternetNetwork() {
+ final List<VcnUnderlyingNetworkTemplate> networkTemplates = new ArrayList();
+
+ networkTemplates.add(
+ new VcnCellUnderlyingNetworkTemplate.Builder().setDun(MATCH_REQUIRED).build());
+ UnderlyingNetworkListener cb = setupControllerAndGetNetworkListener(networkTemplates);
+
+ bringupNetworkAndGetRecord(
+ cb, CBS_NETWORK_CAPABILITIES, networkTemplates, null /* currentlySelected */);
+
+ verify(mNetworkControllerCb, never())
+ .onSelectedUnderlyingNetworkChanged(any(UnderlyingNetworkRecord.class));
+ }
}