Merge "Rename: ReadDmaBufs -> ReadProcfsDmaBufs"
diff --git a/core/api/current.txt b/core/api/current.txt
index 7acd940..c9b5af5 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -21304,7 +21304,7 @@
field public static final int ERROR_RECLAIMED = 1101; // 0x44d
}
- public static final class MediaCodec.CryptoException extends java.lang.RuntimeException {
+ public static final class MediaCodec.CryptoException extends java.lang.RuntimeException implements android.media.MediaDrmThrowable {
ctor public MediaCodec.CryptoException(int, @Nullable String);
method public int getErrorCode();
field @Deprecated public static final int ERROR_FRAME_TOO_LARGE = 8; // 0x8
@@ -21804,7 +21804,7 @@
method public void setMediaDrmSession(@NonNull byte[]) throws android.media.MediaCryptoException;
}
- public final class MediaCryptoException extends java.lang.Exception {
+ public final class MediaCryptoException extends java.lang.Exception implements android.media.MediaDrmThrowable {
ctor public MediaCryptoException(@Nullable String);
}
@@ -22027,7 +22027,7 @@
method public long getTimestampMillis();
}
- public static final class MediaDrm.MediaDrmStateException extends java.lang.IllegalStateException {
+ public static final class MediaDrm.MediaDrmStateException extends java.lang.IllegalStateException implements android.media.MediaDrmThrowable {
method @NonNull public String getDiagnosticInfo();
method public int getErrorCode();
method public boolean isTransient();
@@ -22100,7 +22100,7 @@
@Deprecated @IntDef({android.media.MediaDrm.SECURITY_LEVEL_UNKNOWN, android.media.MediaDrm.SECURITY_LEVEL_SW_SECURE_CRYPTO, android.media.MediaDrm.SECURITY_LEVEL_SW_SECURE_DECODE, android.media.MediaDrm.SECURITY_LEVEL_HW_SECURE_CRYPTO, android.media.MediaDrm.SECURITY_LEVEL_HW_SECURE_DECODE, android.media.MediaDrm.SECURITY_LEVEL_HW_SECURE_ALL}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface MediaDrm.SecurityLevel {
}
- public static final class MediaDrm.SessionException extends java.lang.RuntimeException {
+ public static final class MediaDrm.SessionException extends java.lang.RuntimeException implements android.media.MediaDrmThrowable {
ctor public MediaDrm.SessionException(int, @Nullable String);
method @Deprecated public int getErrorCode();
method public boolean isTransient();
@@ -22108,14 +22108,20 @@
field @Deprecated public static final int ERROR_UNKNOWN = 0; // 0x0
}
- public class MediaDrmException extends java.lang.Exception {
+ public class MediaDrmException extends java.lang.Exception implements android.media.MediaDrmThrowable {
ctor public MediaDrmException(String);
}
- public class MediaDrmResetException extends java.lang.IllegalStateException {
+ public class MediaDrmResetException extends java.lang.IllegalStateException implements android.media.MediaDrmThrowable {
ctor public MediaDrmResetException(String);
}
+ public interface MediaDrmThrowable {
+ method public default int getErrorContext();
+ method public default int getOemError();
+ method public default int getVendorError();
+ }
+
public final class MediaExtractor {
ctor public MediaExtractor();
method public boolean advance();
@@ -41831,6 +41837,9 @@
field public static final int AUTHENTICATION_METHOD_CERT = 1; // 0x1
field public static final int AUTHENTICATION_METHOD_EAP_ONLY = 0; // 0x0
field public static final int EPDG_ADDRESS_CELLULAR_LOC = 3; // 0x3
+ field public static final int EPDG_ADDRESS_IPV4_ONLY = 2; // 0x2
+ field public static final int EPDG_ADDRESS_IPV4_PREFERRED = 0; // 0x0
+ field public static final int EPDG_ADDRESS_IPV6_PREFERRED = 1; // 0x1
field public static final int EPDG_ADDRESS_PCO = 2; // 0x2
field public static final int EPDG_ADDRESS_PLMN = 1; // 0x1
field public static final int EPDG_ADDRESS_STATIC = 0; // 0x0
@@ -41845,6 +41854,7 @@
field public static final String KEY_CHILD_SESSION_AES_CTR_KEY_SIZE_INT_ARRAY = "iwlan.child_session_aes_ctr_key_size_int_array";
field public static final String KEY_DIFFIE_HELLMAN_GROUPS_INT_ARRAY = "iwlan.diffie_hellman_groups_int_array";
field public static final String KEY_DPD_TIMER_SEC_INT = "iwlan.dpd_timer_sec_int";
+ field public static final String KEY_EPDG_ADDRESS_IP_TYPE_PREFERENCE_INT = "iwlan.epdg_address_ip_type_preference_int";
field public static final String KEY_EPDG_ADDRESS_PRIORITY_INT_ARRAY = "iwlan.epdg_address_priority_int_array";
field public static final String KEY_EPDG_AUTHENTICATION_METHOD_INT = "iwlan.epdg_authentication_method_int";
field public static final String KEY_EPDG_PCO_ID_IPV4_INT = "iwlan.epdg_pco_id_ipv4_int";
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index ed2c8eb..8d53959 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -446,6 +446,10 @@
package android.telephony {
+ public class CarrierConfigManager {
+ field public static final String KEY_MIN_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT = "min_udp_port_4500_nat_timeout_sec_int";
+ }
+
public abstract class CellSignalStrength {
method public static int getNumSignalStrengthLevels();
}
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/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/os/Debug.java b/core/java/android/os/Debug.java
index 399f11b..c731a80 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -982,6 +982,43 @@
/**
+ * Wait until a debugger attaches. As soon as a debugger attaches,
+ * suspend all Java threads and send VM_START (a.k.a VM_INIT)
+ * packet.
+ *
+ * @hide
+ */
+ public static void suspendAllAndSendVmStart() {
+ if (!VMDebug.isDebuggingEnabled()) {
+ return;
+ }
+
+ // if DDMS is listening, inform them of our plight
+ System.out.println("Sending WAIT chunk");
+ byte[] data = new byte[] { 0 }; // 0 == "waiting for debugger"
+ Chunk waitChunk = new Chunk(ChunkHandler.type("WAIT"), data, 0, 1);
+ DdmServer.sendChunk(waitChunk);
+
+ // We must wait until a debugger is connected (debug socket is
+ // open and at least one non-DDM JDWP packedt has been received.
+ // This guarantees that oj-libjdwp has been attached and that
+ // ART's default implementation of suspendAllAndSendVmStart has
+ // been replaced with an implementation that will suspendAll and
+ // send VM_START.
+ System.out.println("Waiting for debugger first packet");
+ while (!isDebuggerConnected()) {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ie) {
+ }
+ }
+
+ System.out.println("Debug.suspendAllAndSentVmStart");
+ VMDebug.suspendAllAndSendVmStart();
+ System.out.println("Debug.suspendAllAndSendVmStart, resumed");
+ }
+
+ /**
* Wait until a debugger attaches. As soon as the debugger attaches,
* this returns, so you will need to place a breakpoint after the
* waitForDebugger() call if you want to start tracing immediately.
diff --git a/core/java/android/os/ServiceManager.java b/core/java/android/os/ServiceManager.java
index 394927e..b210c46 100644
--- a/core/java/android/os/ServiceManager.java
+++ b/core/java/android/os/ServiceManager.java
@@ -292,8 +292,10 @@
* If the service is not running, servicemanager will attempt to start it, and this function
* will wait for it to be ready.
*
- * @return {@code null} if the service is not declared in the manifest, or if there are
- * permission problems, or if there are fatal errors.
+ * @throws SecurityException if the process does not have the permissions to check
+ * isDeclared() for the service.
+ * @return {@code null} if the service is not declared in the manifest, or if there
+ * are fatal errors.
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
diff --git a/core/java/android/os/ThreadLocalWorkSource.java b/core/java/android/os/ThreadLocalWorkSource.java
index 894b1cc4..e9adb20 100644
--- a/core/java/android/os/ThreadLocalWorkSource.java
+++ b/core/java/android/os/ThreadLocalWorkSource.java
@@ -39,8 +39,8 @@
*/
public final class ThreadLocalWorkSource {
public static final int UID_NONE = Message.UID_NONE;
- private static final ThreadLocal<Integer> sWorkSourceUid =
- ThreadLocal.withInitial(() -> UID_NONE);
+ private static final ThreadLocal<int []> sWorkSourceUid =
+ ThreadLocal.withInitial(() -> new int[] {UID_NONE});
/**
* Returns the UID to blame for the code currently executed on this thread.
@@ -50,7 +50,7 @@
* <p>It can also be set manually using {@link #setUid(int)}.
*/
public static int getUid() {
- return sWorkSourceUid.get();
+ return sWorkSourceUid.get()[0];
}
/**
@@ -65,7 +65,7 @@
*/
public static long setUid(int uid) {
final long token = getToken();
- sWorkSourceUid.set(uid);
+ sWorkSourceUid.get()[0] = uid;
return token;
}
@@ -73,7 +73,7 @@
* Restores the state using the provided token.
*/
public static void restore(long token) {
- sWorkSourceUid.set(parseUidFromToken(token));
+ sWorkSourceUid.get()[0] = parseUidFromToken(token);
}
/**
@@ -88,7 +88,7 @@
* </pre>
*
* @return a token that can be used to restore the state.
- **/
+ */
public static long clear() {
return setUid(UID_NONE);
}
@@ -98,7 +98,7 @@
}
private static long getToken() {
- return sWorkSourceUid.get();
+ return sWorkSourceUid.get()[0];
}
private ThreadLocalWorkSource() {
diff --git a/core/java/android/security/rkp/IRemoteProvisioning.aidl b/core/java/android/security/rkp/IRemoteProvisioning.aidl
index 23d8159..0efaa89 100644
--- a/core/java/android/security/rkp/IRemoteProvisioning.aidl
+++ b/core/java/android/security/rkp/IRemoteProvisioning.aidl
@@ -58,11 +58,4 @@
*
*/
void getRegistration(String irpcName, IGetRegistrationCallback callback);
-
- /**
- * Cancel any active {@link getRegistration} call associated with the given
- * callback. If no getRegistration call is currently active, this function is
- * a noop.
- */
- void cancelGetRegistration(IGetRegistrationCallback callback);
}
diff --git a/core/java/android/service/controls/OWNERS b/core/java/android/service/controls/OWNERS
new file mode 100644
index 0000000..4bb78c7
--- /dev/null
+++ b/core/java/android/service/controls/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 802726
+asc@google.com
+kozynski@google.com
+juliacr@google.com
\ No newline at end of file
diff --git a/core/java/android/view/InputEventReceiver.java b/core/java/android/view/InputEventReceiver.java
index a24c1f9..492c938 100644
--- a/core/java/android/view/InputEventReceiver.java
+++ b/core/java/android/view/InputEventReceiver.java
@@ -77,7 +77,7 @@
mInputChannel = inputChannel;
mMessageQueue = looper.getQueue();
mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
- inputChannel, mMessageQueue);
+ mInputChannel, mMessageQueue);
mCloseGuard.open("InputEventReceiver.dispose");
}
diff --git a/core/java/android/view/InputEventSender.java b/core/java/android/view/InputEventSender.java
index 9035f3f..64f62c7 100644
--- a/core/java/android/view/InputEventSender.java
+++ b/core/java/android/view/InputEventSender.java
@@ -65,7 +65,7 @@
mInputChannel = inputChannel;
mMessageQueue = looper.getQueue();
mSenderPtr = nativeInit(new WeakReference<InputEventSender>(this),
- inputChannel, mMessageQueue);
+ mInputChannel, mMessageQueue);
mCloseGuard.open("InputEventSender.dispose");
}
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/tests/coretests/src/android/service/controls/OWNERS b/core/tests/coretests/src/android/service/controls/OWNERS
new file mode 100644
index 0000000..bf67034
--- /dev/null
+++ b/core/tests/coretests/src/android/service/controls/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/base:/core/java/android/service/controls/OWNERS
\ No newline at end of file
diff --git a/media/java/android/media/DeniedByServerException.java b/media/java/android/media/DeniedByServerException.java
index 9c1633a..98903ec 100644
--- a/media/java/android/media/DeniedByServerException.java
+++ b/media/java/android/media/DeniedByServerException.java
@@ -24,4 +24,11 @@
public DeniedByServerException(String detailMessage) {
super(detailMessage);
}
+
+ /**
+ * @hide
+ */
+ public DeniedByServerException(String message, int vendorError, int oemError, int context) {
+ super(message, vendorError, oemError, context);
+ }
}
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 220232d..8e8ed6c 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -2472,10 +2472,22 @@
/**
* Thrown when a crypto error occurs while queueing a secure input buffer.
*/
- public final static class CryptoException extends RuntimeException {
+ public final static class CryptoException extends RuntimeException
+ implements MediaDrmThrowable {
public CryptoException(int errorCode, @Nullable String detailMessage) {
- super(detailMessage);
+ this(detailMessage, errorCode, 0, 0, 0);
+ }
+
+ /**
+ * @hide
+ */
+ public CryptoException(String message, int errorCode, int vendorError, int oemError,
+ int errorContext) {
+ super(message);
mErrorCode = errorCode;
+ mVendorError = vendorError;
+ mOemError = oemError;
+ mErrorContext = errorContext;
}
/**
@@ -2594,7 +2606,22 @@
return mErrorCode;
}
- private int mErrorCode;
+ @Override
+ public int getVendorError() {
+ return mVendorError;
+ }
+
+ @Override
+ public int getOemError() {
+ return mOemError;
+ }
+
+ @Override
+ public int getErrorContext() {
+ return mErrorContext;
+ }
+
+ private final int mErrorCode, mVendorError, mOemError, mErrorContext;
}
/**
diff --git a/media/java/android/media/MediaCryptoException.java b/media/java/android/media/MediaCryptoException.java
index 32ddf47..2a472fb 100644
--- a/media/java/android/media/MediaCryptoException.java
+++ b/media/java/android/media/MediaCryptoException.java
@@ -22,8 +22,35 @@
* Exception thrown if MediaCrypto object could not be instantiated or
* if unable to perform an operation on the MediaCrypto object.
*/
-public final class MediaCryptoException extends Exception {
+public final class MediaCryptoException extends Exception implements MediaDrmThrowable {
public MediaCryptoException(@Nullable String detailMessage) {
- super(detailMessage);
+ this(detailMessage, 0, 0, 0);
}
+
+ /**
+ * @hide
+ */
+ public MediaCryptoException(String message, int vendorError, int oemError, int errorContext) {
+ super(message);
+ mVendorError = vendorError;
+ mOemError = oemError;
+ mErrorContext = errorContext;
+ }
+
+ @Override
+ public int getVendorError() {
+ return mVendorError;
+ }
+
+ @Override
+ public int getOemError() {
+ return mOemError;
+ }
+
+ @Override
+ public int getErrorContext() {
+ return mErrorContext;
+ }
+
+ private final int mVendorError, mOemError, mErrorContext;
}
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 2a04ebb..a3fa43d 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -664,21 +664,33 @@
* strategy and details about each possible return value from {@link
* MediaDrmStateException#getErrorCode()}.
*/
- public static final class MediaDrmStateException extends java.lang.IllegalStateException {
- private final int mErrorCode;
+ public static final class MediaDrmStateException extends java.lang.IllegalStateException
+ implements MediaDrmThrowable {
+ private final int mErrorCode, mVendorError, mOemError, mErrorContext;
private final String mDiagnosticInfo;
/**
* @hide
*/
public MediaDrmStateException(int errorCode, @Nullable String detailMessage) {
+ this(detailMessage, errorCode, 0, 0, 0);
+ }
+
+ /**
+ * @hide
+ */
+ public MediaDrmStateException(String detailMessage, int errorCode,
+ int vendorError, int oemError, int errorContext) {
super(detailMessage);
mErrorCode = errorCode;
+ mVendorError = vendorError;
+ mOemError = oemError;
+ mErrorContext = errorContext;
// TODO get this from DRM session
final String sign = errorCode < 0 ? "neg_" : "";
mDiagnosticInfo =
- "android.media.MediaDrm.error_" + sign + Math.abs(errorCode);
+ "android.media.MediaDrm.error_" + sign + Math.abs(errorCode);
}
@@ -696,6 +708,21 @@
return mErrorCode;
}
+ @Override
+ public int getVendorError() {
+ return mVendorError;
+ }
+
+ @Override
+ public int getOemError() {
+ return mOemError;
+ }
+
+ @Override
+ public int getErrorContext() {
+ return mErrorContext;
+ }
+
/**
* Returns true if the {@link MediaDrmStateException} is a transient
* issue, perhaps due to resource constraints, and that the operation
@@ -727,10 +754,22 @@
* {@link #isTransient()} to determine whether the app should retry the
* failing operation.
*/
- public static final class SessionException extends RuntimeException {
+ public static final class SessionException extends RuntimeException
+ implements MediaDrmThrowable {
public SessionException(int errorCode, @Nullable String detailMessage) {
+ this(detailMessage, errorCode, 0, 0, 0);
+ }
+
+ /**
+ * @hide
+ */
+ public SessionException(String detailMessage, int errorCode, int vendorError, int oemError,
+ int errorContext) {
super(detailMessage);
mErrorCode = errorCode;
+ mVendorError = vendorError;
+ mOemError = oemError;
+ mErrorContext = errorContext;
}
/**
@@ -769,6 +808,21 @@
return mErrorCode;
}
+ @Override
+ public int getVendorError() {
+ return mVendorError;
+ }
+
+ @Override
+ public int getOemError() {
+ return mOemError;
+ }
+
+ @Override
+ public int getErrorContext() {
+ return mErrorContext;
+ }
+
/**
* Returns true if the {@link SessionException} is a transient
* issue, perhaps due to resource constraints, and that the operation
@@ -779,7 +833,7 @@
return mErrorCode == ERROR_RESOURCE_CONTENTION;
}
- private final int mErrorCode;
+ private final int mErrorCode, mVendorError, mOemError, mErrorContext;
}
/**
diff --git a/media/java/android/media/MediaDrmException.java b/media/java/android/media/MediaDrmException.java
index d547574..58c5dd0 100644
--- a/media/java/android/media/MediaDrmException.java
+++ b/media/java/android/media/MediaDrmException.java
@@ -19,8 +19,35 @@
/**
* Base class for MediaDrm exceptions
*/
-public class MediaDrmException extends Exception {
+public class MediaDrmException extends Exception implements MediaDrmThrowable {
public MediaDrmException(String detailMessage) {
- super(detailMessage);
+ this(detailMessage, 0, 0, 0);
}
+
+ /**
+ * @hide
+ */
+ public MediaDrmException(String message, int vendorError, int oemError, int errorContext) {
+ super(message);
+ mVendorError = vendorError;
+ mOemError = oemError;
+ mErrorContext = errorContext;
+ }
+
+ @Override
+ public int getVendorError() {
+ return mVendorError;
+ }
+
+ @Override
+ public int getOemError() {
+ return mOemError;
+ }
+
+ @Override
+ public int getErrorContext() {
+ return mErrorContext;
+ }
+
+ private final int mVendorError, mOemError, mErrorContext;
}
diff --git a/media/java/android/media/MediaDrmResetException.java b/media/java/android/media/MediaDrmResetException.java
index 3b2da1e..ccd723b 100644
--- a/media/java/android/media/MediaDrmResetException.java
+++ b/media/java/android/media/MediaDrmResetException.java
@@ -21,7 +21,7 @@
* due to a restart of the mediaserver process. To continue, the app must
* release the MediaDrm object, then create and initialize a new one.
*/
-public class MediaDrmResetException extends IllegalStateException {
+public class MediaDrmResetException extends IllegalStateException implements MediaDrmThrowable {
public MediaDrmResetException(String detailMessage) {
super(detailMessage);
}
diff --git a/media/java/android/media/MediaDrmThrowable.java b/media/java/android/media/MediaDrmThrowable.java
new file mode 100644
index 0000000..38480d7
--- /dev/null
+++ b/media/java/android/media/MediaDrmThrowable.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+/**
+ * A @{@link Throwable} thrown from {@link MediaDrm} or @{@link MediaCrypto} APIs
+ */
+public interface MediaDrmThrowable {
+ /**
+ * Returns {@link MediaDrm} plugin vendor defined error code associated with this {@link
+ * MediaDrmThrowable}.
+ * <p>
+ * Please consult the {@link MediaDrm} plugin vendor for details on the error code.
+ *
+ * @return an error code defined by the {@link MediaDrm} plugin vendor if available,
+ * otherwise 0.
+ */
+ public default int getVendorError() {
+ return 0;
+ }
+
+ /**
+ * Returns OEM or SOC specific error code associated with this {@link
+ * MediaDrmThrowable}.
+ * <p>
+ * Please consult the {@link MediaDrm} plugin, chip, or device vendor for details on the
+ * error code.
+ *
+ * @return an OEM or SOC specific error code if available, otherwise 0.
+ */
+ public default int getOemError() {
+ return 0;
+ }
+
+ /**
+ * Returns {@link MediaDrm} plugin vendor defined error context associated with this {@link
+ * MediaDrmThrowable}.
+ * <p>
+ * Please consult the {@link MediaDrm} plugin vendor for details on the error context.
+ *
+ * @return an opaque integer that would help the @{@link MediaDrm} vendor locate the
+ * source of the error if available, otherwise 0.
+ */
+ public default int getErrorContext() {
+ return 0;
+ }
+
+}
diff --git a/media/java/android/media/NotProvisionedException.java b/media/java/android/media/NotProvisionedException.java
index 32b8151..4b5a816 100644
--- a/media/java/android/media/NotProvisionedException.java
+++ b/media/java/android/media/NotProvisionedException.java
@@ -26,4 +26,11 @@
public NotProvisionedException(String detailMessage) {
super(detailMessage);
}
+
+ /**
+ * @hide
+ */
+ public NotProvisionedException(String message, int vendorError, int oemError, int context) {
+ super(message, vendorError, oemError, context);
+ }
}
diff --git a/media/java/android/media/ResourceBusyException.java b/media/java/android/media/ResourceBusyException.java
index a5abe21..7aaf7eb 100644
--- a/media/java/android/media/ResourceBusyException.java
+++ b/media/java/android/media/ResourceBusyException.java
@@ -24,4 +24,11 @@
public ResourceBusyException(String detailMessage) {
super(detailMessage);
}
+
+ /**
+ * @hide
+ */
+ public ResourceBusyException(String message, int vendorError, int oemError, int context) {
+ super(message, vendorError, oemError, context);
+ }
}
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 1183ca3..d8705a7 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -1285,7 +1285,7 @@
CHECK(clazz.get() != NULL);
jmethodID constructID =
- env->GetMethodID(clazz.get(), "<init>", "(ILjava/lang/String;)V");
+ env->GetMethodID(clazz.get(), "<init>", "(Ljava/lang/String;IIII)V");
CHECK(constructID != NULL);
std::string defaultMsg = "Unknown Error";
@@ -1335,14 +1335,14 @@
break;
}
- std::string msgStr(msg != NULL ? msg : defaultMsg.c_str());
- if (crypto != NULL) {
- msgStr = DrmUtils::GetExceptionMessage(err, msgStr.c_str(), crypto);
- }
- jstring msgObj = env->NewStringUTF(msgStr.c_str());
+ std::string originalMsg(msg != NULL ? msg : defaultMsg.c_str());
+ DrmStatus dStatus(err, originalMsg.c_str());
+ std::string detailedMsg(DrmUtils::GetExceptionMessage(dStatus, defaultMsg.c_str(), crypto));
+ jstring msgObj = env->NewStringUTF(detailedMsg.c_str());
jthrowable exception =
- (jthrowable)env->NewObject(clazz.get(), constructID, jerr, msgObj);
+ (jthrowable)env->NewObject(clazz.get(), constructID, msgObj, jerr,
+ dStatus.getCdmErr(), dStatus.getOemErr(), dStatus.getContext());
env->Throw(exception);
}
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index c9d920f..681d76a 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -244,6 +244,20 @@
}
return arrayList;
}
+
+int drmThrowException(JNIEnv* env, const char *className, const DrmStatus &err, const char *msg) {
+ using namespace android::jnihelp;
+ jstring _detailMessage = CreateExceptionMsg(env, msg);
+ int _status = ThrowException(env, className, "(Ljava/lang/String;III)V",
+ _detailMessage,
+ err.getCdmErr(),
+ err.getOemErr(),
+ err.getContext());
+ if (_detailMessage != NULL) {
+ env->DeleteLocalRef(_detailMessage);
+ }
+ return _status;
+}
} // namespace anonymous
// ----------------------------------------------------------------------------
@@ -393,8 +407,8 @@
jint jerr = MediaErrorToJavaError(err);
jobject exception = env->NewObject(gFields.stateException.classId,
- gFields.stateException.init, static_cast<int>(jerr),
- env->NewStringUTF(msg));
+ gFields.stateException.init, env->NewStringUTF(msg), static_cast<int>(jerr),
+ err.getCdmErr(), err.getOemErr(), err.getContext());
env->Throw(static_cast<jthrowable>(exception));
}
@@ -411,10 +425,13 @@
}
jobject exception = env->NewObject(gFields.sessionException.classId,
- gFields.sessionException.init, static_cast<int>(err),
- env->NewStringUTF(msg));
+ gFields.sessionException.init,
+ env->NewStringUTF(msg),
+ jErrorCode,
+ err.getCdmErr(),
+ err.getOemErr(),
+ err.getContext());
- env->SetIntField(exception, gFields.sessionException.errorCode, jErrorCode);
env->Throw(static_cast<jthrowable>(exception));
}
@@ -437,13 +454,13 @@
jniThrowException(env, "java/lang/UnsupportedOperationException", msg);
return true;
} else if (err == ERROR_DRM_NOT_PROVISIONED) {
- jniThrowException(env, "android/media/NotProvisionedException", msg);
+ drmThrowException(env, "android/media/NotProvisionedException", err, msg);
return true;
} else if (err == ERROR_DRM_RESOURCE_BUSY) {
- jniThrowException(env, "android/media/ResourceBusyException", msg);
+ drmThrowException(env, "android/media/ResourceBusyException", err, msg);
return true;
} else if (err == ERROR_DRM_DEVICE_REVOKED) {
- jniThrowException(env, "android/media/DeniedByServerException", msg);
+ drmThrowException(env, "android/media/DeniedByServerException", err, msg);
return true;
} else if (err == DEAD_OBJECT) {
jniThrowException(env, "android/media/MediaDrmResetException", msg);
@@ -915,11 +932,11 @@
gFields.arraylistClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
- GET_METHOD_ID(gFields.stateException.init, clazz, "<init>", "(ILjava/lang/String;)V");
+ GET_METHOD_ID(gFields.stateException.init, clazz, "<init>", "(Ljava/lang/String;IIII)V");
gFields.stateException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
FIND_CLASS(clazz, "android/media/MediaDrm$SessionException");
- GET_METHOD_ID(gFields.sessionException.init, clazz, "<init>", "(ILjava/lang/String;)V");
+ GET_METHOD_ID(gFields.sessionException.init, clazz, "<init>", "(Ljava/lang/String;IIII)V");
gFields.sessionException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
GET_FIELD_ID(gFields.sessionException.errorCode, clazz, "mErrorCode", "I");
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/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 19dbee7..c15e419 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -140,6 +140,7 @@
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnProfile;
import com.android.modules.utils.build.SdkLevel;
+import com.android.net.module.util.BinderUtils;
import com.android.net.module.util.NetdUtils;
import com.android.net.module.util.NetworkStackConstants;
import com.android.server.DeviceIdleInternal;
@@ -2783,6 +2784,16 @@
return hasIPV6 && !hasIPV4;
}
+ private void setVpnNetworkPreference(String session, Set<Range<Integer>> ranges) {
+ BinderUtils.withCleanCallingIdentity(
+ () -> mConnectivityManager.setVpnDefaultForUids(session, ranges));
+ }
+
+ private void clearVpnNetworkPreference(String session) {
+ BinderUtils.withCleanCallingIdentity(
+ () -> mConnectivityManager.setVpnDefaultForUids(session, Collections.EMPTY_LIST));
+ }
+
/**
* Internal class managing IKEv2/IPsec VPN connectivity
*
@@ -2894,6 +2905,9 @@
(r, exe) -> {
Log.d(TAG, "Runnable " + r + " rejected by the mExecutor");
});
+ setVpnNetworkPreference(mSessionKey,
+ createUserAndRestrictedProfilesRanges(mUserId,
+ mConfig.allowedApplications, mConfig.disallowedApplications));
}
@Override
@@ -3047,7 +3061,6 @@
mConfig.dnsServers.addAll(dnsAddrStrings);
mConfig.underlyingNetworks = new Network[] {network};
- mConfig.disallowedApplications = getAppExclusionList(mPackage);
networkAgent = mNetworkAgent;
@@ -3750,6 +3763,7 @@
mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
mConnectivityDiagnosticsManager.unregisterConnectivityDiagnosticsCallback(
mDiagnosticsCallback);
+ clearVpnNetworkPreference(mSessionKey);
mExecutor.shutdown();
}
@@ -4310,6 +4324,7 @@
mConfig.requiresInternetValidation = profile.requiresInternetValidation;
mConfig.excludeLocalRoutes = profile.excludeLocalRoutes;
mConfig.allowBypass = profile.isBypassable;
+ mConfig.disallowedApplications = getAppExclusionList(mPackage);
switch (profile.type) {
case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS:
@@ -4462,6 +4477,9 @@
.setUids(createUserAndRestrictedProfilesRanges(
mUserId, null /* allowedApplications */, excludedApps))
.build();
+ setVpnNetworkPreference(getSessionKeyLocked(),
+ createUserAndRestrictedProfilesRanges(mUserId,
+ mConfig.allowedApplications, mConfig.disallowedApplications));
doSendNetworkCapabilities(mNetworkAgent, mNetworkCapabilities);
}
}
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/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index dbf05f1..ed4ba0d 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -4212,8 +4212,8 @@
}
private boolean forceSuspendInternal(int uid) {
- try {
- synchronized (mLock) {
+ synchronized (mLock) {
+ try {
mForceSuspendActive = true;
// Place the system in an non-interactive state
for (int idx = 0; idx < mPowerGroups.size(); idx++) {
@@ -4223,16 +4223,14 @@
// Disable all the partial wake locks as well
updateWakeLockDisabledStatesLocked();
- }
- Slog.i(TAG, "Force-Suspending (uid " + uid + ")...");
- boolean success = mNativeWrapper.nativeForceSuspend();
- if (!success) {
- Slog.i(TAG, "Force-Suspending failed in native.");
- }
- return success;
- } finally {
- synchronized (mLock) {
+ Slog.i(TAG, "Force-Suspending (uid " + uid + ")...");
+ boolean success = mNativeWrapper.nativeForceSuspend();
+ if (!success) {
+ Slog.i(TAG, "Force-Suspending failed in native.");
+ }
+ return success;
+ } finally {
mForceSuspendActive = false;
// Re-enable wake locks once again.
updateWakeLockDisabledStatesLocked();
diff --git a/services/core/java/com/android/server/security/rkp/RemoteProvisioningRegistration.java b/services/core/java/com/android/server/security/rkp/RemoteProvisioningRegistration.java
new file mode 100644
index 0000000..868f34b
--- /dev/null
+++ b/services/core/java/com/android/server/security/rkp/RemoteProvisioningRegistration.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.security.rkp;
+
+import android.os.CancellationSignal;
+import android.os.OperationCanceledException;
+import android.os.OutcomeReceiver;
+import android.security.rkp.IGetKeyCallback;
+import android.security.rkp.IRegistration;
+import android.security.rkp.service.RegistrationProxy;
+import android.security.rkp.service.RemotelyProvisionedKey;
+import android.util.Log;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
+
+/**
+ * Implements android.security.rkp.IRegistration as a thin wrapper around the java code
+ * exported by com.android.rkp.
+ *
+ * @hide
+ */
+final class RemoteProvisioningRegistration extends IRegistration.Stub {
+ static final String TAG = RemoteProvisioningService.TAG;
+ private final ConcurrentHashMap<IGetKeyCallback, CancellationSignal> mOperations =
+ new ConcurrentHashMap<>();
+ private final RegistrationProxy mRegistration;
+ private final Executor mExecutor;
+
+ private class GetKeyReceiver implements OutcomeReceiver<RemotelyProvisionedKey, Exception> {
+ IGetKeyCallback mCallback;
+ GetKeyReceiver(IGetKeyCallback callback) {
+ mCallback = callback;
+ }
+
+ @Override
+ public void onResult(RemotelyProvisionedKey result) {
+ mOperations.remove(mCallback);
+ Log.i(TAG, "Successfully fetched key for client " + mCallback.hashCode());
+ android.security.rkp.RemotelyProvisionedKey parcelable =
+ new android.security.rkp.RemotelyProvisionedKey();
+ parcelable.keyBlob = result.getKeyBlob();
+ parcelable.encodedCertChain = result.getEncodedCertChain();
+ wrapCallback(() -> mCallback.onSuccess(parcelable));
+ }
+
+ @Override
+ public void onError(Exception e) {
+ mOperations.remove(mCallback);
+ if (e instanceof OperationCanceledException) {
+ Log.i(TAG, "Operation cancelled for client " + mCallback.hashCode());
+ wrapCallback(mCallback::onCancel);
+ } else {
+ Log.e(TAG, "Error fetching key for client " + mCallback.hashCode(), e);
+ wrapCallback(() -> mCallback.onError(e.getMessage()));
+ }
+ }
+ }
+
+ RemoteProvisioningRegistration(RegistrationProxy registration, Executor executor) {
+ mRegistration = registration;
+ mExecutor = executor;
+ }
+
+ @Override
+ public void getKey(int keyId, IGetKeyCallback callback) {
+ CancellationSignal cancellationSignal = new CancellationSignal();
+ if (mOperations.putIfAbsent(callback, cancellationSignal) != null) {
+ Log.e(TAG, "Client can only request one call at a time " + callback.hashCode());
+ throw new IllegalArgumentException(
+ "Callback is already associated with an existing operation: "
+ + callback.hashCode());
+ }
+
+ try {
+ Log.i(TAG, "Fetching key " + keyId + " for client " + callback.hashCode());
+ mRegistration.getKeyAsync(keyId, cancellationSignal, mExecutor,
+ new GetKeyReceiver(callback));
+ } catch (Exception e) {
+ Log.e(TAG, "getKeyAsync threw an exception for client " + callback.hashCode(), e);
+ mOperations.remove(callback);
+ wrapCallback(() -> callback.onError(e.getMessage()));
+ }
+ }
+
+ @Override
+ public void cancelGetKey(IGetKeyCallback callback) {
+ CancellationSignal cancellationSignal = mOperations.remove(callback);
+ if (cancellationSignal == null) {
+ throw new IllegalArgumentException(
+ "Invalid client in cancelGetKey: " + callback.hashCode());
+ }
+
+ Log.i(TAG, "Requesting cancellation for client " + callback.hashCode());
+ cancellationSignal.cancel();
+ }
+
+ @Override
+ public void storeUpgradedKey(byte[] oldKeyBlob, byte[] newKeyBlob) {
+ // TODO(b/262748535)
+ Log.e(TAG, "RegistrationBinder.storeUpgradedKey NOT YET IMPLEMENTED");
+ }
+
+ interface CallbackRunner {
+ void run() throws Exception;
+ }
+
+ private void wrapCallback(CallbackRunner callback) {
+ // Exceptions resulting from notifications to IGetKeyCallback objects can only be logged,
+ // since getKey execution is asynchronous, and there's no way for an exception to be
+ // properly handled up the stack.
+ try {
+ callback.run();
+ } catch (Exception e) {
+ Log.e(TAG, "Error invoking callback on client binder", e);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/security/rkp/RemoteProvisioningService.java b/services/core/java/com/android/server/security/rkp/RemoteProvisioningService.java
index 65a4b38..cd1a968 100644
--- a/services/core/java/com/android/server/security/rkp/RemoteProvisioningService.java
+++ b/services/core/java/com/android/server/security/rkp/RemoteProvisioningService.java
@@ -20,9 +20,7 @@
import android.os.Binder;
import android.os.OutcomeReceiver;
import android.os.RemoteException;
-import android.security.rkp.IGetKeyCallback;
import android.security.rkp.IGetRegistrationCallback;
-import android.security.rkp.IRegistration;
import android.security.rkp.IRemoteProvisioning;
import android.security.rkp.service.RegistrationProxy;
import android.util.Log;
@@ -30,6 +28,7 @@
import com.android.server.SystemService;
import java.time.Duration;
+import java.util.concurrent.Executor;
/**
* Implements the remote provisioning system service. This service is backed by a mainline
@@ -43,6 +42,35 @@
private static final Duration CREATE_REGISTRATION_TIMEOUT = Duration.ofSeconds(10);
private final RemoteProvisioningImpl mBinderImpl = new RemoteProvisioningImpl();
+ private static class RegistrationReceiver implements
+ OutcomeReceiver<RegistrationProxy, Exception> {
+ private final Executor mExecutor;
+ private final IGetRegistrationCallback mCallback;
+
+ RegistrationReceiver(Executor executor, IGetRegistrationCallback callback) {
+ mExecutor = executor;
+ mCallback = callback;
+ }
+
+ @Override
+ public void onResult(RegistrationProxy registration) {
+ try {
+ mCallback.onSuccess(new RemoteProvisioningRegistration(registration, mExecutor));
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling success callback " + mCallback.hashCode(), e);
+ }
+ }
+
+ @Override
+ public void onError(Exception error) {
+ try {
+ mCallback.onError(error.toString());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling error callback " + mCallback.hashCode(), e);
+ }
+ }
+ }
+
/** @hide */
public RemoteProvisioningService(Context context) {
super(context);
@@ -54,73 +82,20 @@
}
private final class RemoteProvisioningImpl extends IRemoteProvisioning.Stub {
-
- final class RegistrationBinder extends IRegistration.Stub {
- static final String TAG = RemoteProvisioningService.TAG;
- private final RegistrationProxy mRegistration;
-
- RegistrationBinder(RegistrationProxy registration) {
- mRegistration = registration;
- }
-
- @Override
- public void getKey(int keyId, IGetKeyCallback callback) {
- Log.e(TAG, "RegistrationBinder.getKey NOT YET IMPLEMENTED");
- }
-
- @Override
- public void cancelGetKey(IGetKeyCallback callback) {
- Log.e(TAG, "RegistrationBinder.cancelGetKey NOT YET IMPLEMENTED");
- }
-
- @Override
- public void storeUpgradedKey(byte[] oldKeyBlob, byte[] newKeyBlob) {
- Log.e(TAG, "RegistrationBinder.storeUpgradedKey NOT YET IMPLEMENTED");
- }
- }
-
@Override
public void getRegistration(String irpcName, IGetRegistrationCallback callback)
throws RemoteException {
final int callerUid = Binder.getCallingUidOrThrow();
final long callingIdentity = Binder.clearCallingIdentity();
+ final Executor executor = getContext().getMainExecutor();
try {
Log.i(TAG, "getRegistration(" + irpcName + ")");
- RegistrationProxy.createAsync(
- getContext(),
- callerUid,
- irpcName,
- CREATE_REGISTRATION_TIMEOUT,
- getContext().getMainExecutor(),
- new OutcomeReceiver<>() {
- @Override
- public void onResult(RegistrationProxy registration) {
- try {
- callback.onSuccess(new RegistrationBinder(registration));
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling success callback", e);
- }
- }
-
- @Override
- public void onError(Exception error) {
- try {
- callback.onError(error.toString());
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling error callback", e);
- }
- }
- });
+ RegistrationProxy.createAsync(getContext(), callerUid, irpcName,
+ CREATE_REGISTRATION_TIMEOUT, executor,
+ new RegistrationReceiver(executor, callback));
} finally {
Binder.restoreCallingIdentity(callingIdentity);
}
}
-
- @Override
- public void cancelGetRegistration(IGetRegistrationCallback callback)
- throws RemoteException {
- Log.i(TAG, "cancelGetRegistration()");
- callback.onError("cancelGetRegistration not yet implemented");
- }
}
}
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/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index ff09163..330c098 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -1085,10 +1085,14 @@
// Use launch-adjacent-flag-root if launching with launch-adjacent flag.
if ((launchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0
&& mLaunchAdjacentFlagRootTask != null) {
- // If the adjacent launch is coming from the same root, launch to adjacent root instead.
- if (sourceTask != null && mLaunchAdjacentFlagRootTask.getAdjacentTaskFragment() != null
+ if (sourceTask != null && sourceTask == candidateTask) {
+ // Do nothing when task that is getting opened is same as the source.
+ } else if (sourceTask != null
+ && mLaunchAdjacentFlagRootTask.getAdjacentTaskFragment() != null
&& (sourceTask == mLaunchAdjacentFlagRootTask
|| sourceTask.isDescendantOf(mLaunchAdjacentFlagRootTask))) {
+ // If the adjacent launch is coming from the same root, launch to
+ // adjacent root instead.
return mLaunchAdjacentFlagRootTask.getAdjacentTaskFragment().asTask();
} else {
return mLaunchAdjacentFlagRootTask;
diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java
index 0fdf40d..27ba676 100644
--- a/telephony/java/android/telephony/AccessNetworkConstants.java
+++ b/telephony/java/android/telephony/AccessNetworkConstants.java
@@ -605,9 +605,9 @@
EUTRAN_ARFCN_FREQUENCY_BAND_41(
EutranBand.BAND_41, 2496000, 39650, 41589, 2496000, 39650, 41589),
EUTRAN_ARFCN_FREQUENCY_BAND_42(
- EutranBand.BAND_42, 3400000, 41950, 43589, 3400000, 41950, 43589),
+ EutranBand.BAND_42, 3400000, 41590, 43589, 3400000, 41590, 43589),
EUTRAN_ARFCN_FREQUENCY_BAND_43(
- EutranBand.BAND_43, 3600000, 43950, 45589, 3600000, 43950, 45589),
+ EutranBand.BAND_43, 3600000, 43590, 45589, 3600000, 43590, 45589),
EUTRAN_ARFCN_FREQUENCY_BAND_44(
EutranBand.BAND_44, 703000, 45590, 46589, 703000, 45590, 46589),
EUTRAN_ARFCN_FREQUENCY_BAND_45(
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 12d1bc3..d8c1b57e3 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -4308,6 +4308,18 @@
"data_switch_validation_timeout_long";
/**
+ * The minimum timeout of UDP port 4500 NAT / firewall entries on the Internet PDN of this
+ * carrier network. This will be used by Android platform VPNs to tune IPsec NAT keepalive
+ * interval. If this value is too low to provide uninterrupted inbound connectivity, then
+ * Android system VPNs may indicate to applications that the VPN cannot support long-lived
+ * TCP connections.
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final String KEY_MIN_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT =
+ "min_udp_port_4500_nat_timeout_sec_int";
+
+ /**
* Specifies whether the system should prefix the EAP method to the anonymous identity.
* The following prefix will be added if this key is set to TRUE:
* EAP-AKA: "0"
@@ -8008,6 +8020,14 @@
public static final String KEY_SUPPORTS_EAP_AKA_FAST_REAUTH_BOOL =
KEY_PREFIX + "supports_eap_aka_fast_reauth_bool";
+ /**
+ * Type of IP preference used to prioritize ePDG servers. Possible values are
+ * {@link #EPDG_ADDRESS_IPV4_PREFERRED}, {@link #EPDG_ADDRESS_IPV6_PREFERRED},
+ * {@link #EPDG_ADDRESS_IPV4_ONLY}
+ */
+ public static final String KEY_EPDG_ADDRESS_IP_TYPE_PREFERENCE_INT =
+ KEY_PREFIX + "epdg_address_ip_type_preference_int";
+
/** @hide */
@IntDef({AUTHENTICATION_METHOD_EAP_ONLY, AUTHENTICATION_METHOD_CERT})
public @interface AuthenticationMethodType {}
@@ -8072,6 +8092,39 @@
*/
public static final int ID_TYPE_KEY_ID = 11;
+ /** @hide */
+ @IntDef({
+ EPDG_ADDRESS_IPV4_PREFERRED,
+ EPDG_ADDRESS_IPV6_PREFERRED,
+ EPDG_ADDRESS_IPV4_ONLY,
+ EPDG_ADDRESS_IPV6_ONLY,
+ EPDG_ADDRESS_SYSTEM_PREFERRED
+ })
+ public @interface EpdgAddressIpPreference {}
+
+ /** Prioritize IPv4 ePDG addresses. */
+ public static final int EPDG_ADDRESS_IPV4_PREFERRED = 0;
+
+ /** Prioritize IPv6 ePDG addresses */
+ public static final int EPDG_ADDRESS_IPV6_PREFERRED = 1;
+
+ /** Use IPv4 ePDG addresses only. */
+ public static final int EPDG_ADDRESS_IPV4_ONLY = 2;
+
+ /** Use IPv6 ePDG addresses only.
+ * @hide
+ */
+ public static final int EPDG_ADDRESS_IPV6_ONLY = 3;
+
+ /** Follow the priority from DNS resolution results, which are sorted by using RFC6724
+ * algorithm.
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc6724#section-6">RFC 6724, Default Address
+ * Selection for Internet Protocol Version 6 (IPv6)</a>
+ * @hide
+ */
+ public static final int EPDG_ADDRESS_SYSTEM_PREFERRED = 4;
+
private Iwlan() {}
private static PersistableBundle getDefaults() {
@@ -8155,7 +8208,7 @@
defaults.putInt(KEY_EPDG_PCO_ID_IPV6_INT, 0);
defaults.putInt(KEY_EPDG_PCO_ID_IPV4_INT, 0);
defaults.putBoolean(KEY_SUPPORTS_EAP_AKA_FAST_REAUTH_BOOL, false);
-
+ defaults.putInt(KEY_EPDG_ADDRESS_IP_TYPE_PREFERENCE_INT, EPDG_ADDRESS_IPV4_PREFERRED);
return defaults;
}
}
@@ -9130,6 +9183,7 @@
sDefaults.putStringArray(KEY_MMI_TWO_DIGIT_NUMBER_PATTERN_STRING_ARRAY, new String[0]);
sDefaults.putInt(KEY_PARAMETERS_USED_FOR_LTE_SIGNAL_BAR_INT,
CellSignalStrengthLte.USE_RSRP);
+ sDefaults.putInt(KEY_MIN_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT, 300);
// Default wifi configurations.
sDefaults.putAll(Wifi.getDefaults());
sDefaults.putBoolean(ENABLE_EAP_METHOD_PREFIX_BOOL, false);
diff --git a/telephony/java/android/telephony/data/QosBearerFilter.java b/telephony/java/android/telephony/data/QosBearerFilter.java
index 0ab7b61..a0d9c1bd 100644
--- a/telephony/java/android/telephony/data/QosBearerFilter.java
+++ b/telephony/java/android/telephony/data/QosBearerFilter.java
@@ -130,6 +130,10 @@
return precedence;
}
+ public int getProtocol() {
+ return protocol;
+ }
+
public static class PortRange implements Parcelable {
int start;
int end;
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));
+ }
}