summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/net/UidRange.java9
-rw-r--r--core/java/android/os/Debug.java8
-rw-r--r--core/java/com/android/internal/os/Zygote.java2
-rw-r--r--core/java/com/android/internal/os/ZygoteConnection.java4
-rw-r--r--core/java/com/android/internal/os/ZygoteInit.java34
-rw-r--r--core/java/com/android/internal/os/ZygoteServer.java2
-rw-r--r--core/jni/android_os_Debug.cpp12
-rw-r--r--keystore/java/android/security/keystore/KeyGenParameterSpec.java41
-rw-r--r--keystore/java/android/security/keystore/KeyProperties.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java21
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java21
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java19
-rw-r--r--services/core/java/com/android/server/connectivity/PermissionMonitor.java33
-rw-r--r--services/core/java/com/android/server/vcn/VcnGatewayConnection.java120
-rw-r--r--tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java64
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java43
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java5
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java5
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java5
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java5
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java25
21 files changed, 386 insertions, 101 deletions
diff --git a/core/java/android/net/UidRange.java b/core/java/android/net/UidRange.java
index 3bc0f9ca4e6a..b172ccc4e370 100644
--- a/core/java/android/net/UidRange.java
+++ b/core/java/android/net/UidRange.java
@@ -21,6 +21,7 @@ import static android.os.UserHandle.PER_USER_RANGE;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.UserHandle;
import java.util.Collection;
@@ -45,6 +46,14 @@ public final class UidRange implements Parcelable {
return new UidRange(userId * PER_USER_RANGE, (userId + 1) * PER_USER_RANGE - 1);
}
+ /** Creates a UidRange for the specified user. */
+ public static UidRange createForUser(UserHandle user) {
+ final UserHandle nextUser = UserHandle.of(user.getIdentifier() + 1);
+ final int start = UserHandle.getUid(user, 0 /* appId */);
+ final int end = UserHandle.getUid(nextUser, 0) - 1;
+ return new UidRange(start, end);
+ }
+
/** Returns the smallest user Id which is contained in this UidRange */
public int getStartUser() {
return start / PER_USER_RANGE;
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index ea282afb8b8e..903bea3dc2ce 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -2560,6 +2560,14 @@ public final class Debug
public static native long getDmabufTotalExportedKb();
/**
+ * Return total memory size in kilobytes for DMA-BUFs exported from the DMA-BUF
+ * heaps frameworks or -1 in the case of an error.
+ *
+ * @hide
+ */
+ public static native long getDmabufHeapTotalExportedKb();
+
+ /**
* Return memory size in kilobytes allocated for ION heaps or -1 if
* /sys/kernel/ion/total_heaps_kb could not be read.
*
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index a41018000d77..65beb9360241 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -590,7 +590,7 @@ public final class Zygote {
static Runnable forkUsap(LocalServerSocket usapPoolSocket,
int[] sessionSocketRawFDs,
boolean isPriorityFork) {
- FileDescriptor[] pipeFDs = null;
+ FileDescriptor[] pipeFDs;
try {
pipeFDs = Os.pipe2(O_CLOEXEC);
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 6573e4217a7f..5a576ebbc442 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -505,8 +505,8 @@ class ZygoteConnection {
parsedArgs.mDisabledCompatChanges,
parsedArgs.mRemainingArgs, null /* classLoader */);
} else {
- return ZygoteInit.childZygoteInit(parsedArgs.mTargetSdkVersion,
- parsedArgs.mRemainingArgs, null /* classLoader */);
+ return ZygoteInit.childZygoteInit(
+ parsedArgs.mRemainingArgs /* classLoader */);
}
}
}
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 7fde5474ec92..ef1c50f43681 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -117,7 +117,7 @@ public class ZygoteInit {
/**
* Controls whether we should preload resources during zygote init.
*/
- public static final boolean PRELOAD_RESOURCES = true;
+ private static final boolean PRELOAD_RESOURCES = true;
private static final int UNPRIVILEGED_UID = 9999;
private static final int UNPRIVILEGED_GID = 9999;
@@ -159,7 +159,7 @@ public class ZygoteInit {
sPreloadComplete = true;
}
- public static void lazyPreload() {
+ static void lazyPreload() {
Preconditions.checkState(!sPreloadComplete);
Log.i(TAG, "Lazily preloading resources.");
@@ -364,7 +364,7 @@ public class ZygoteInit {
}
if ("true".equals(prop)) {
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ResetJitCounters");
- runtime.resetJitCounters();
+ VMRuntime.resetJitCounters();
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
}
@@ -418,8 +418,6 @@ public class ZygoteInit {
* larger.
*/
private static void preloadResources() {
- final VMRuntime runtime = VMRuntime.getRuntime();
-
try {
mResources = Resources.getSystem();
mResources.startPreloading();
@@ -463,9 +461,7 @@ public class ZygoteInit {
int N = ar.length();
for (int i = 0; i < N; i++) {
int id = ar.getResourceId(i, 0);
- if (false) {
- Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
- }
+
if (id != 0) {
if (mResources.getColorStateList(id, null) == null) {
throw new IllegalArgumentException(
@@ -483,9 +479,7 @@ public class ZygoteInit {
int N = ar.length();
for (int i = 0; i < N; i++) {
int id = ar.getResourceId(i, 0);
- if (false) {
- Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
- }
+
if (id != 0) {
if (mResources.getDrawable(id, null) == null) {
throw new IllegalArgumentException(
@@ -688,13 +682,12 @@ public class ZygoteInit {
final String packageName = "*";
final String outputPath = null;
final int dexFlags = 0;
- final String compilerFilter = systemServerFilter;
final String uuid = StorageManager.UUID_PRIVATE_INTERNAL;
final String seInfo = null;
final int targetSdkVersion = 0; // SystemServer targets the system's SDK version
try {
installd.dexopt(classPathElement, Process.SYSTEM_UID, packageName,
- instructionSet, dexoptNeeded, outputPath, dexFlags, compilerFilter,
+ instructionSet, dexoptNeeded, outputPath, dexFlags, systemServerFilter,
uuid, classLoaderContext, seInfo, false /* downgrade */,
targetSdkVersion, /*profileName*/ null, /*dexMetadataPath*/ null,
"server-dexopt");
@@ -770,7 +763,7 @@ public class ZygoteInit {
capabilities &= ((long) data[0].effective) | (((long) data[1].effective) << 32);
/* Hardcoded command line to start the system server */
- String args[] = {
+ String[] args = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,"
@@ -781,7 +774,7 @@ public class ZygoteInit {
"--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
"com.android.server.SystemServer",
};
- ZygoteArguments parsedArgs = null;
+ ZygoteArguments parsedArgs;
int pid;
@@ -870,7 +863,7 @@ public class ZygoteInit {
* @param argv Command line arguments used to specify the Zygote's configuration.
*/
@UnsupportedAppUsage
- public static void main(String argv[]) {
+ public static void main(String[] argv) {
ZygoteServer zygoteServer = null;
// Mark zygote start. This ensures that thread creation will throw
@@ -1029,7 +1022,7 @@ public class ZygoteInit {
* are enabled)
* @param argv arg strings
*/
- public static final Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
+ public static Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
String[] argv, ClassLoader classLoader) {
if (RuntimeInit.DEBUG) {
Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
@@ -1049,11 +1042,10 @@ public class ZygoteInit {
* to zygoteInit(), which skips calling into initialization routines that start the Binder
* threadpool.
*/
- static final Runnable childZygoteInit(
- int targetSdkVersion, String[] argv, ClassLoader classLoader) {
+ static Runnable childZygoteInit(String[] argv) {
RuntimeInit.Arguments args = new RuntimeInit.Arguments(argv);
- return RuntimeInit.findStaticMain(args.startClass, args.startArgs, classLoader);
+ return RuntimeInit.findStaticMain(args.startClass, args.startArgs, /* classLoader= */null);
}
- private static final native void nativeZygoteInit();
+ private static native void nativeZygoteInit();
}
diff --git a/core/java/com/android/internal/os/ZygoteServer.java b/core/java/com/android/internal/os/ZygoteServer.java
index db7cbbca450e..585ddf6ddf98 100644
--- a/core/java/com/android/internal/os/ZygoteServer.java
+++ b/core/java/com/android/internal/os/ZygoteServer.java
@@ -411,7 +411,7 @@ class ZygoteServer {
}
}
- void resetUsapRefillState() {
+ private void resetUsapRefillState() {
mUsapPoolRefillAction = UsapPoolRefillAction.NONE;
mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;
}
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 223b4dcc0549..0e3db46bd0c9 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -826,6 +826,16 @@ static jlong android_os_Debug_getDmabufTotalExportedKb(JNIEnv* env, jobject claz
return dmabufTotalSizeKb;
}
+static jlong android_os_Debug_getDmabufHeapTotalExportedKb(JNIEnv* env, jobject clazz) {
+ jlong dmabufHeapTotalSizeKb = -1;
+ uint64_t size;
+
+ if (meminfo::ReadDmabufHeapTotalExportedKb(&size)) {
+ dmabufHeapTotalSizeKb = size;
+ }
+ return dmabufHeapTotalSizeKb;
+}
+
static jlong android_os_Debug_getIonPoolsSizeKb(JNIEnv* env, jobject clazz) {
jlong poolsSizeKb = -1;
uint64_t size;
@@ -983,6 +993,8 @@ static const JNINativeMethod gMethods[] = {
(void*)android_os_Debug_getDmabufTotalExportedKb },
{ "getGpuDmaBufUsageKb", "()J",
(void*)android_os_Debug_getGpuDmaBufUsageKb },
+ { "getDmabufHeapTotalExportedKb", "()J",
+ (void*)android_os_Debug_getDmabufHeapTotalExportedKb },
{ "getIonPoolsSizeKb", "()J",
(void*)android_os_Debug_getIonPoolsSizeKb },
{ "getDmabufMappedSizeKb", "()J",
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index e92eaca2b6e9..2b0d7e53b749 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -236,6 +236,47 @@ import javax.security.auth.x500.X500Principal;
* keyStore.load(null);
* key = (SecretKey) keyStore.getKey("key2", null);
* }</pre>
+ *
+ * <p><h3 id="example:ecdh">Example: EC key for ECDH key agreement</h3>
+ * This example illustrates how to generate an elliptic curve key pair, used to establish a shared
+ * secret with another party using ECDH key agreement.
+ * <pre> {@code
+ * KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(
+ * KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
+ * keyPairGenerator.initialize(
+ * new KeyGenParameterSpec.Builder(
+ * "eckeypair",
+ * KeyProperties.PURPOSE_AGREE_KEY)
+ * .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
+ * .build());
+ * KeyPair myKeyPair = keyPairGenerator.generateKeyPair();
+ *
+ * // Exchange public keys with server. A new ephemeral key MUST be used for every message.
+ * PublicKey serverEphemeralPublicKey; // Ephemeral key received from server.
+ *
+ * // Create a shared secret based on our private key and the other party's public key.
+ * KeyAgreement keyAgreement = KeyAgreement.getInstance("ECDH", "AndroidKeyStore");
+ * keyAgreement.init(myKeyPair.getPrivate());
+ * keyAgreement.doPhase(serverEphemeralPublicKey, true);
+ * byte[] sharedSecret = keyAgreement.generateSecret();
+ *
+ * // sharedSecret cannot safely be used as a key yet. We must run it through a key derivation
+ * // function with some other data: "salt" and "info". Salt is an optional random value,
+ * // omitted in this example. It's good practice to include both public keys and any other
+ * // key negotiation data in info. Here we use the public keys and a label that indicates
+ * // messages encrypted with this key are coming from the server.
+ * byte[] salt = {};
+ * ByteArrayOutputStream info = new ByteArrayOutputStream();
+ * info.write("ECDH secp256r1 AES-256-GCM-SIV\0".getBytes(StandardCharsets.UTF_8));
+ * info.write(myKeyPair.getPublic().getEncoded());
+ * info.write(serverEphemeralPublicKey.getEncoded());
+ *
+ * // This example uses the Tink library and the HKDF key derivation function.
+ * AesGcmSiv key = new AesGcmSiv(Hkdf.computeHkdf(
+ * "HMACSHA256", sharedSecret, salt, info.toByteArray(), 32));
+ * byte[] associatedData = {};
+ * return key.decrypt(ciphertext, associatedData);
+ * }
*/
public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAuthArgs {
diff --git a/keystore/java/android/security/keystore/KeyProperties.java b/keystore/java/android/security/keystore/KeyProperties.java
index 3ebca6ad302d..293ab05e0b10 100644
--- a/keystore/java/android/security/keystore/KeyProperties.java
+++ b/keystore/java/android/security/keystore/KeyProperties.java
@@ -100,6 +100,15 @@ public abstract class KeyProperties {
/**
* Purpose of key: creating a shared ECDH secret through key agreement.
+ *
+ * <p>A key having this purpose can be combined with the elliptic curve public key of another
+ * party to establish a shared secret over an insecure channel. It should be used as a
+ * parameter to {@link javax.crypto.KeyAgreement#init(java.security.Key)} (a complete example is
+ * available <a
+ * href="{@docRoot}reference/android/security/keystore/KeyGenParameterSpec#example:ecdh"
+ * >here</a>).
+ * See <a href="https://en.wikipedia.org/wiki/Elliptic-curve_Diffie%E2%80%93Hellman">this
+ * article</a> for a more detailed explanation.
*/
public static final int PURPOSE_AGREE_KEY = 1 << 6;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 75f4809d752f..dfa1b7e01809 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -62,6 +62,7 @@ import android.telephony.TelephonyManager;
import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
+import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.view.View;
import android.view.ViewGroup;
@@ -294,6 +295,13 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
*/
private final SparseIntArray mLastSimStates = new SparseIntArray();
+ /**
+ * Indicates if a SIM card had the SIM PIN enabled during the initialization, before
+ * reaching the SIM_STATE_READY state. The flag is reset to false at SIM_STATE_READY.
+ * Index is the slotId - in case of multiple SIM cards.
+ */
+ private final SparseBooleanArray mSimWasLocked = new SparseBooleanArray();
+
private boolean mDeviceInteractive;
private boolean mGoingToSleep;
@@ -465,10 +473,10 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
}
}
- boolean simWasLocked;
+ boolean lastSimStateWasLocked;
synchronized (KeyguardViewMediator.this) {
int lastState = mLastSimStates.get(slotId);
- simWasLocked = (lastState == TelephonyManager.SIM_STATE_PIN_REQUIRED
+ lastSimStateWasLocked = (lastState == TelephonyManager.SIM_STATE_PIN_REQUIRED
|| lastState == TelephonyManager.SIM_STATE_PUK_REQUIRED);
mLastSimStates.append(slotId, simState);
}
@@ -492,17 +500,19 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
if (simState == TelephonyManager.SIM_STATE_ABSENT) {
// MVNO SIMs can become transiently NOT_READY when switching networks,
// so we should only lock when they are ABSENT.
- if (simWasLocked) {
+ if (lastSimStateWasLocked) {
if (DEBUG_SIM_STATES) Log.d(TAG, "SIM moved to ABSENT when the "
+ "previous state was locked. Reset the state.");
resetStateLocked();
}
+ mSimWasLocked.append(slotId, false);
}
}
break;
case TelephonyManager.SIM_STATE_PIN_REQUIRED:
case TelephonyManager.SIM_STATE_PUK_REQUIRED:
synchronized (KeyguardViewMediator.this) {
+ mSimWasLocked.append(slotId, true);
if (!mShowing) {
if (DEBUG_SIM_STATES) Log.d(TAG,
"INTENT_VALUE_ICC_LOCKED and keygaurd isn't "
@@ -529,9 +539,10 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
case TelephonyManager.SIM_STATE_READY:
synchronized (KeyguardViewMediator.this) {
if (DEBUG_SIM_STATES) Log.d(TAG, "READY, reset state? " + mShowing);
- if (mShowing && simWasLocked) {
+ if (mShowing && mSimWasLocked.get(slotId, false)) {
if (DEBUG_SIM_STATES) Log.d(TAG, "SIM moved to READY when the "
- + "previous state was locked. Reset the state.");
+ + "previously was locked. Reset the state.");
+ mSimWasLocked.append(slotId, false);
resetStateLocked();
}
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index c2e50a685ca0..154e1831ceee 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -4983,12 +4983,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- private void onUserAdded(int userId) {
- mPermissionMonitor.onUserAdded(userId);
+ private void onUserAdded(UserHandle user) {
+ mPermissionMonitor.onUserAdded(user);
}
- private void onUserRemoved(int userId) {
- mPermissionMonitor.onUserRemoved(userId);
+ private void onUserRemoved(UserHandle user) {
+ mPermissionMonitor.onUserRemoved(user);
}
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@@ -4996,15 +4996,18 @@ public class ConnectivityService extends IConnectivityManager.Stub
public void onReceive(Context context, Intent intent) {
ensureRunningOnConnectivityServiceThread();
final String action = intent.getAction();
- final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+ final UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER);
- // UserId should be filled for below intents, check the existence.
- if (userId == UserHandle.USER_NULL) return;
+ // User should be filled for below intents, check the existence.
+ if (user == null) {
+ Log.wtf(TAG, intent.getAction() + " broadcast without EXTRA_USER");
+ return;
+ }
if (Intent.ACTION_USER_ADDED.equals(action)) {
- onUserAdded(userId);
+ onUserAdded(user);
} else if (Intent.ACTION_USER_REMOVED.equals(action)) {
- onUserRemoved(userId);
+ onUserRemoved(user);
} else {
Log.wtf(TAG, "received unexpected intent: " + action);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 126d04f794f5..661d49690a00 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -13767,6 +13767,15 @@ public class ActivityManagerService extends IActivityManager.Stub
totalPss -= totalMemtrackGraphics;
totalPss += dmabufMapped;
}
+
+ // totalDmabufHeapExported is included in totalExportedDmabuf above and hence do not
+ // need to be added to kernelUsed.
+ final long totalDmabufHeapExported = Debug.getDmabufHeapTotalExportedKb();
+ if (totalDmabufHeapExported >= 0) {
+ pw.print("DMA-BUF Heaps: ");
+ pw.println(stringifyKBSize(totalDmabufHeapExported));
+ }
+
final long totalDmabufHeapPool = Debug.getDmabufHeapPoolsSizeKb();
if (totalDmabufHeapPool >= 0) {
pw.print("DMA-BUF Heaps pool: ");
@@ -14619,6 +14628,16 @@ public class ActivityManagerService extends IActivityManager.Stub
totalPss -= totalMemtrackGraphics;
totalPss += dmabufMapped;
}
+
+ // These are included in the totalExportedDmabuf above and hence do not need to be added
+ // to kernelUsed.
+ final long totalExportedDmabufHeap = Debug.getDmabufHeapTotalExportedKb();
+ if (totalExportedDmabufHeap >= 0) {
+ memInfoBuilder.append("DMA-BUF Heap: ");
+ memInfoBuilder.append(stringifyKBSize(totalExportedDmabufHeap));
+ memInfoBuilder.append("\n");
+ }
+
final long totalDmabufHeapPool = Debug.getDmabufHeapPoolsSizeKb();
if (totalDmabufHeapPool >= 0) {
memInfoBuilder.append("DMA-BUF Heaps pool: ");
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index 8d21f6f0f59f..8bf188696c27 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -83,9 +83,8 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
private final INetd mNetd;
private final Dependencies mDeps;
- // Values are User IDs.
@GuardedBy("this")
- private final Set<Integer> mUsers = new HashSet<>();
+ private final Set<UserHandle> mUsers = new HashSet<>();
// Keys are app uids. Values are true for SYSTEM permission and false for NETWORK permission.
@GuardedBy("this")
@@ -173,10 +172,7 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms);
}
- final List<UserHandle> users = mUserManager.getUserHandles(true /* excludeDying */);
- for (UserHandle user : users) {
- mUsers.add(user.getIdentifier());
- }
+ mUsers.addAll(mUserManager.getUserHandles(true /* excludeDying */));
final SparseArray<ArraySet<String>> systemPermission =
SystemConfig.getInstance().getSystemPermissions();
@@ -259,16 +255,15 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
return array;
}
- private void update(Set<Integer> users, Map<Integer, Boolean> apps, boolean add) {
+ private void update(Set<UserHandle> users, Map<Integer, Boolean> apps, boolean add) {
List<Integer> network = new ArrayList<>();
List<Integer> system = new ArrayList<>();
for (Entry<Integer, Boolean> app : apps.entrySet()) {
List<Integer> list = app.getValue() ? system : network;
- for (int user : users) {
- final UserHandle handle = UserHandle.of(user);
- if (handle == null) continue;
+ for (UserHandle user : users) {
+ if (user == null) continue;
- list.add(UserHandle.getUid(handle, app.getKey()));
+ list.add(UserHandle.getUid(user, app.getKey()));
}
}
try {
@@ -291,14 +286,10 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
*
* @hide
*/
- public synchronized void onUserAdded(int user) {
- if (user < 0) {
- loge("Invalid user in onUserAdded: " + user);
- return;
- }
+ public synchronized void onUserAdded(@NonNull UserHandle user) {
mUsers.add(user);
- Set<Integer> users = new HashSet<>();
+ Set<UserHandle> users = new HashSet<>();
users.add(user);
update(users, mApps, true);
}
@@ -310,14 +301,10 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
*
* @hide
*/
- public synchronized void onUserRemoved(int user) {
- if (user < 0) {
- loge("Invalid user in onUserRemoved: " + user);
- return;
- }
+ public synchronized void onUserRemoved(@NonNull UserHandle user) {
mUsers.remove(user);
- Set<Integer> users = new HashSet<>();
+ Set<UserHandle> users = new HashSet<>();
users.add(user);
update(users, mApps, false);
}
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 8aab3a66ada3..12590eba81f8 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -38,10 +38,12 @@ import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkAgent;
+import android.net.NetworkAgent.ValidationStatus;
import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities;
import android.net.RouteInfo;
import android.net.TelephonyNetworkSpecifier;
+import android.net.Uri;
import android.net.annotations.PolicyDirection;
import android.net.ipsec.ike.ChildSessionCallback;
import android.net.ipsec.ike.ChildSessionConfiguration;
@@ -151,6 +153,9 @@ public class VcnGatewayConnection extends StateMachine {
@VisibleForTesting(visibility = Visibility.PRIVATE)
static final String RETRY_TIMEOUT_ALARM = TAG + "_RETRY_TIMEOUT_ALARM";
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ static final String SAFEMODE_TIMEOUT_ALARM = TAG + "_SAFEMODE_TIMEOUT_ALARM";
+
private static final int[] MERGED_CAPABILITIES =
new int[] {NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_NOT_ROAMING};
private static final int ARG_NOT_PRESENT = Integer.MIN_VALUE;
@@ -167,6 +172,9 @@ public class VcnGatewayConnection extends StateMachine {
@VisibleForTesting(visibility = Visibility.PRIVATE)
static final int TEARDOWN_TIMEOUT_SECONDS = 5;
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ static final int SAFEMODE_TIMEOUT_SECONDS = 30;
+
private interface EventInfo {}
/**
@@ -409,6 +417,23 @@ public class VcnGatewayConnection extends StateMachine {
// TODO(b/178426520): implement handling of this event
private static final int EVENT_SUBSCRIPTIONS_CHANGED = 9;
+ /**
+ * Sent when this VcnGatewayConnection has entered Safemode.
+ *
+ * <p>A VcnGatewayConnection enters Safemode when it takes over {@link
+ * #SAFEMODE_TIMEOUT_SECONDS} to enter {@link ConnectedState}.
+ *
+ * <p>When a VcnGatewayConnection enters safe mode, it will fire {@link
+ * VcnGatewayStatusCallback#onEnteredSafemode()} to notify its Vcn. The Vcn will then shut down
+ * its VcnGatewayConnectin(s).
+ *
+ * <p>Relevant in DisconnectingState, ConnectingState, ConnectedState (if the Vcn Network is not
+ * validated yet), and RetryTimeoutState.
+ *
+ * @param arg1 The "all" token; this signal is always honored.
+ */
+ private static final int EVENT_SAFEMODE_TIMEOUT_EXCEEDED = 10;
+
@VisibleForTesting(visibility = Visibility.PRIVATE)
@NonNull
final DisconnectedState mDisconnectedState = new DisconnectedState();
@@ -520,11 +545,13 @@ public class VcnGatewayConnection extends StateMachine {
* <p>Set in Connected state, always @NonNull in Connected, Migrating states, @Nullable
* otherwise.
*/
- private NetworkAgent mNetworkAgent;
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ NetworkAgent mNetworkAgent;
@Nullable private WakeupMessage mTeardownTimeoutAlarm;
@Nullable private WakeupMessage mDisconnectRequestAlarm;
@Nullable private WakeupMessage mRetryTimeoutAlarm;
+ @Nullable private WakeupMessage mSafemodeTimeoutAlarm;
public VcnGatewayConnection(
@NonNull VcnContext vcnContext,
@@ -611,6 +638,7 @@ public class VcnGatewayConnection extends StateMachine {
cancelTeardownTimeoutAlarm();
cancelDisconnectRequestAlarm();
cancelRetryTimeoutAlarm();
+ cancelSafemodeAlarm();
mUnderlyingNetworkTracker.teardown();
}
@@ -899,6 +927,30 @@ public class VcnGatewayConnection extends StateMachine {
removeEqualMessages(EVENT_RETRY_TIMEOUT_EXPIRED);
}
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ void setSafemodeAlarm() {
+ // Only schedule a NEW alarm if none is already set.
+ if (mSafemodeTimeoutAlarm != null) {
+ return;
+ }
+
+ final Message delayedMessage = obtainMessage(EVENT_SAFEMODE_TIMEOUT_EXCEEDED, TOKEN_ALL);
+ mSafemodeTimeoutAlarm =
+ createScheduledAlarm(
+ SAFEMODE_TIMEOUT_ALARM,
+ delayedMessage,
+ TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS));
+ }
+
+ private void cancelSafemodeAlarm() {
+ if (mSafemodeTimeoutAlarm != null) {
+ mSafemodeTimeoutAlarm.cancel();
+ mSafemodeTimeoutAlarm = null;
+ }
+
+ removeEqualMessages(EVENT_SAFEMODE_TIMEOUT_EXCEEDED);
+ }
+
private void sessionLost(int token, @Nullable Exception exception) {
sendMessageAndAcquireWakeLock(
EVENT_SESSION_LOST, token, new EventSessionLostInfo(exception));
@@ -1072,6 +1124,8 @@ public class VcnGatewayConnection extends StateMachine {
if (mIkeSession != null || mNetworkAgent != null) {
Slog.wtf(TAG, "Active IKE Session or NetworkAgent in DisconnectedState");
}
+
+ cancelSafemodeAlarm();
}
@Override
@@ -1095,6 +1149,12 @@ public class VcnGatewayConnection extends StateMachine {
break;
}
}
+
+ @Override
+ protected void exitState() {
+ // Safe to blindly set up, as it is cancelled and cleared on entering this state
+ setSafemodeAlarm();
+ }
}
private abstract class ActiveBaseState extends BaseState {
@@ -1185,6 +1245,10 @@ public class VcnGatewayConnection extends StateMachine {
transitionTo(mDisconnectedState);
}
break;
+ case EVENT_SAFEMODE_TIMEOUT_EXCEEDED:
+ mGatewayStatusCallback.onEnteredSafemode();
+ mSafemodeTimeoutAlarm = null;
+ break;
default:
logUnhandledMessage(msg);
break;
@@ -1267,6 +1331,10 @@ public class VcnGatewayConnection extends StateMachine {
case EVENT_DISCONNECT_REQUESTED:
handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason);
break;
+ case EVENT_SAFEMODE_TIMEOUT_EXCEEDED:
+ mGatewayStatusCallback.onEnteredSafemode();
+ mSafemodeTimeoutAlarm = null;
+ break;
default:
logUnhandledMessage(msg);
break;
@@ -1310,6 +1378,14 @@ public class VcnGatewayConnection extends StateMachine {
public void unwanted() {
teardownAsynchronously();
}
+
+ @Override
+ public void onValidationStatus(
+ @ValidationStatus int status, @Nullable Uri redirectUri) {
+ if (status == NetworkAgent.VALIDATION_STATUS_VALID) {
+ clearFailedAttemptCounterAndSafeModeAlarm();
+ }
+ }
};
agent.register();
@@ -1318,6 +1394,14 @@ public class VcnGatewayConnection extends StateMachine {
return agent;
}
+ protected void clearFailedAttemptCounterAndSafeModeAlarm() {
+ mVcnContext.ensureRunningOnLooperThread();
+
+ // Validated connection, clear failed attempt counter
+ mFailedAttempts = 0;
+ cancelSafemodeAlarm();
+ }
+
protected void applyTransform(
int token,
@NonNull IpSecTunnelInterface tunnelIface,
@@ -1325,7 +1409,7 @@ public class VcnGatewayConnection extends StateMachine {
@NonNull IpSecTransform transform,
int direction) {
try {
- // TODO: Set underlying network of tunnel interface
+ // TODO(b/180163196): Set underlying network of tunnel interface
// Transforms do not need to be persisted; the IkeSession will keep them alive
mIpSecManager.applyTunnelModeTransform(tunnelIface, direction, transform);
@@ -1397,9 +1481,6 @@ public class VcnGatewayConnection extends StateMachine {
teardownAsynchronously();
}
}
-
- // Successful connection, clear failed attempt counter
- mFailedAttempts = 0;
}
@Override
@@ -1436,6 +1517,10 @@ public class VcnGatewayConnection extends StateMachine {
case EVENT_DISCONNECT_REQUESTED:
handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason);
break;
+ case EVENT_SAFEMODE_TIMEOUT_EXCEEDED:
+ mGatewayStatusCallback.onEnteredSafemode();
+ mSafemodeTimeoutAlarm = null;
+ break;
default:
logUnhandledMessage(msg);
break;
@@ -1455,6 +1540,7 @@ public class VcnGatewayConnection extends StateMachine {
// mUnderlying assumed non-null, given check above.
// If network changed, migrate. Otherwise, update any existing networkAgent.
if (oldUnderlying == null || !oldUnderlying.network.equals(mUnderlying.network)) {
+ Slog.v(TAG, "Migrating to new network: " + mUnderlying.network);
mIkeSession.setNetwork(mUnderlying.network);
} else {
// oldUnderlying is non-null & underlying network itself has not changed
@@ -1478,8 +1564,19 @@ public class VcnGatewayConnection extends StateMachine {
mNetworkAgent = buildNetworkAgent(tunnelIface, childConfig);
} else {
updateNetworkAgent(tunnelIface, mNetworkAgent, childConfig);
+
+ // mNetworkAgent not null, so the VCN Network has already been established. Clear
+ // the failed attempt counter and safe mode alarm since this transition is complete.
+ clearFailedAttemptCounterAndSafeModeAlarm();
}
}
+
+ @Override
+ protected void exitState() {
+ // Attempt to set the safe mode alarm - this requires the Vcn Network being validated
+ // while in ConnectedState (which cancels the previous alarm)
+ setSafemodeAlarm();
+ }
}
/**
@@ -1526,6 +1623,10 @@ public class VcnGatewayConnection extends StateMachine {
case EVENT_DISCONNECT_REQUESTED:
handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason);
break;
+ case EVENT_SAFEMODE_TIMEOUT_EXCEEDED:
+ mGatewayStatusCallback.onEnteredSafemode();
+ mSafemodeTimeoutAlarm = null;
+ break;
default:
logUnhandledMessage(msg);
break;
@@ -1708,6 +1809,15 @@ public class VcnGatewayConnection extends StateMachine {
}
@Override
+ public void onIpSecTransformsMigrated(
+ @NonNull IpSecTransform inIpSecTransform,
+ @NonNull IpSecTransform outIpSecTransform) {
+ Slog.v(TAG, "ChildTransformsMigrated; token " + mToken);
+ onIpSecTransformCreated(inIpSecTransform, IpSecManager.DIRECTION_IN);
+ onIpSecTransformCreated(outIpSecTransform, IpSecManager.DIRECTION_OUT);
+ }
+
+ @Override
public void onIpSecTransformDeleted(@NonNull IpSecTransform transform, int direction) {
// Nothing to be done; no references to the IpSecTransform are held, and this transform
// will be closed by the IKE library.
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index 3556c72776dc..8f5ae97bc4c5 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -89,8 +89,8 @@ import java.util.Set;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class PermissionMonitorTest {
- private static final int MOCK_USER1 = 0;
- private static final int MOCK_USER2 = 1;
+ private static final UserHandle MOCK_USER1 = UserHandle.of(0);
+ private static final UserHandle MOCK_USER2 = UserHandle.of(1);
private static final int MOCK_UID1 = 10001;
private static final int MOCK_UID2 = 10086;
private static final int SYSTEM_UID1 = 1000;
@@ -123,10 +123,7 @@ public class PermissionMonitorTest {
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
when(mUserManager.getUserHandles(eq(true))).thenReturn(
- Arrays.asList(new UserHandle[] {
- new UserHandle(MOCK_USER1),
- new UserHandle(MOCK_USER2),
- }));
+ Arrays.asList(new UserHandle[] { MOCK_USER1, MOCK_USER2 }));
mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService, mDeps));
@@ -184,7 +181,8 @@ public class PermissionMonitorTest {
return packageInfo;
}
- private static PackageInfo buildPackageInfo(boolean hasSystemPermission, int uid, int userId) {
+ private static PackageInfo buildPackageInfo(boolean hasSystemPermission, int uid,
+ UserHandle user) {
final PackageInfo pkgInfo;
if (hasSystemPermission) {
pkgInfo = systemPackageInfoWithPermissions(
@@ -192,7 +190,7 @@ public class PermissionMonitorTest {
} else {
pkgInfo = packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED, new String[] {}, "");
}
- pkgInfo.applicationInfo.uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
+ pkgInfo.applicationInfo.uid = UserHandle.getUid(user, UserHandle.getAppId(uid));
return pkgInfo;
}
@@ -382,8 +380,8 @@ public class PermissionMonitorTest {
}).when(mockNetd).networkClearPermissionForUser(any(int[].class));
}
- public void expectPermission(Boolean permission, int[] users, int[] apps) {
- for (final int user : users) {
+ public void expectPermission(Boolean permission, UserHandle[] users, int[] apps) {
+ for (final UserHandle user : users) {
for (final int app : apps) {
final int uid = UserHandle.getUid(user, app);
if (!mApps.containsKey(uid)) {
@@ -396,8 +394,8 @@ public class PermissionMonitorTest {
}
}
- public void expectNoPermission(int[] users, int[] apps) {
- for (final int user : users) {
+ public void expectNoPermission(UserHandle[] users, int[] apps) {
+ for (final UserHandle user : users) {
for (final int app : apps) {
final int uid = UserHandle.getUid(user, app);
if (mApps.containsKey(uid)) {
@@ -425,46 +423,48 @@ public class PermissionMonitorTest {
// Add SYSTEM_PACKAGE2, expect only have network permission.
mPermissionMonitor.onUserAdded(MOCK_USER1);
- addPackageForUsers(new int[]{MOCK_USER1}, SYSTEM_PACKAGE2, SYSTEM_UID);
- mNetdMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1}, new int[]{SYSTEM_UID});
+ addPackageForUsers(new UserHandle[]{MOCK_USER1}, SYSTEM_PACKAGE2, SYSTEM_UID);
+ mNetdMonitor.expectPermission(NETWORK, new UserHandle[]{MOCK_USER1}, new int[]{SYSTEM_UID});
// Add SYSTEM_PACKAGE1, expect permission escalate.
- addPackageForUsers(new int[]{MOCK_USER1}, SYSTEM_PACKAGE1, SYSTEM_UID);
- mNetdMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1}, new int[]{SYSTEM_UID});
+ addPackageForUsers(new UserHandle[]{MOCK_USER1}, SYSTEM_PACKAGE1, SYSTEM_UID);
+ mNetdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1}, new int[]{SYSTEM_UID});
mPermissionMonitor.onUserAdded(MOCK_USER2);
- mNetdMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1, MOCK_USER2},
+ mNetdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2},
new int[]{SYSTEM_UID});
- addPackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, MOCK_PACKAGE1, MOCK_UID1);
- mNetdMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1, MOCK_USER2},
+ addPackageForUsers(new UserHandle[]{MOCK_USER1, MOCK_USER2}, MOCK_PACKAGE1, MOCK_UID1);
+ mNetdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2},
new int[]{SYSTEM_UID});
- mNetdMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1, MOCK_USER2},
+ mNetdMonitor.expectPermission(NETWORK, new UserHandle[]{MOCK_USER1, MOCK_USER2},
new int[]{MOCK_UID1});
// Remove MOCK_UID1, expect no permission left for all user.
mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
- removePackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, MOCK_PACKAGE1, MOCK_UID1);
- mNetdMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2}, new int[]{MOCK_UID1});
+ removePackageForUsers(new UserHandle[]{MOCK_USER1, MOCK_USER2}, MOCK_PACKAGE1, MOCK_UID1);
+ mNetdMonitor.expectNoPermission(new UserHandle[]{MOCK_USER1, MOCK_USER2},
+ new int[]{MOCK_UID1});
// Remove SYSTEM_PACKAGE1, expect permission downgrade.
when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{SYSTEM_PACKAGE2});
- removePackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, SYSTEM_PACKAGE1, SYSTEM_UID);
- mNetdMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1, MOCK_USER2},
+ removePackageForUsers(new UserHandle[]{MOCK_USER1, MOCK_USER2},
+ SYSTEM_PACKAGE1, SYSTEM_UID);
+ mNetdMonitor.expectPermission(NETWORK, new UserHandle[]{MOCK_USER1, MOCK_USER2},
new int[]{SYSTEM_UID});
mPermissionMonitor.onUserRemoved(MOCK_USER1);
- mNetdMonitor.expectPermission(NETWORK, new int[]{MOCK_USER2}, new int[]{SYSTEM_UID});
+ mNetdMonitor.expectPermission(NETWORK, new UserHandle[]{MOCK_USER2}, new int[]{SYSTEM_UID});
// Remove all packages, expect no permission left.
when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{});
- removePackageForUsers(new int[]{MOCK_USER2}, SYSTEM_PACKAGE2, SYSTEM_UID);
- mNetdMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2},
+ removePackageForUsers(new UserHandle[]{MOCK_USER2}, SYSTEM_PACKAGE2, SYSTEM_UID);
+ mNetdMonitor.expectNoPermission(new UserHandle[]{MOCK_USER1, MOCK_USER2},
new int[]{SYSTEM_UID, MOCK_UID1});
// Remove last user, expect no redundant clearPermission is invoked.
mPermissionMonitor.onUserRemoved(MOCK_USER2);
- mNetdMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2},
+ mNetdMonitor.expectNoPermission(new UserHandle[]{MOCK_USER1, MOCK_USER2},
new int[]{SYSTEM_UID, MOCK_UID1});
}
@@ -548,14 +548,14 @@ public class PermissionMonitorTest {
// Normal package add/remove operations will trigger multiple intent for uids corresponding to
// each user. To simulate generic package operations, the onPackageAdded/Removed will need to be
// called multiple times with the uid corresponding to each user.
- private void addPackageForUsers(int[] users, String packageName, int uid) {
- for (final int user : users) {
+ private void addPackageForUsers(UserHandle[] users, String packageName, int uid) {
+ for (final UserHandle user : users) {
mPermissionMonitor.onPackageAdded(packageName, UserHandle.getUid(user, uid));
}
}
- private void removePackageForUsers(int[] users, String packageName, int uid) {
- for (final int user : users) {
+ private void removePackageForUsers(UserHandle[] users, String packageName, int uid) {
+ for (final UserHandle user : users) {
mPermissionMonitor.onPackageRemoved(packageName, UserHandle.getUid(user, uid));
}
}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index faa8b234cf51..e7154802f1f2 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -34,8 +34,10 @@ import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
import android.net.LinkProperties;
+import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
import androidx.test.filters.SmallTest;
@@ -73,6 +75,11 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
}
@Test
+ public void testEnterStateDoesNotCancelSafemodeAlarm() {
+ verifySafemodeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+ }
+
+ @Test
public void testNullNetworkDoesNotTriggerDisconnect() throws Exception {
mGatewayConnection
.getUnderlyingNetworkTrackerCallback()
@@ -121,7 +128,24 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
}
@Test
+ public void testMigratedTransformsAreApplied() throws Exception {
+ getChildSessionCallback()
+ .onIpSecTransformsMigrated(makeDummyIpSecTransform(), makeDummyIpSecTransform());
+ mTestLooper.dispatchAll();
+
+ for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT}) {
+ verify(mIpSecSvc)
+ .applyTunnelModeTransform(
+ eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(direction), anyInt(), any());
+ }
+ assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
+ }
+
+ @Test
public void testChildOpenedRegistersNetwork() throws Exception {
+ // Verify scheduled but not canceled when entering ConnectedState
+ verifySafemodeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+
final VcnChildSessionConfiguration mMockChildSessionConfig =
mock(VcnChildSessionConfiguration.class);
doReturn(Collections.singletonList(TEST_INTERNAL_ADDR))
@@ -163,24 +187,41 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
for (int cap : mConfig.getAllExposedCapabilities()) {
assertTrue(nc.hasCapability(cap));
}
+
+ // Now that Vcn Network is up, notify it as validated and verify the Safemode alarm is
+ // canceled
+ mGatewayConnection.mNetworkAgent.onValidationStatus(
+ NetworkAgent.VALIDATION_STATUS_VALID, null /* redirectUri */);
+ verify(mSafemodeTimeoutAlarm).cancel();
}
@Test
public void testChildSessionClosedTriggersDisconnect() throws Exception {
+ // Verify scheduled but not canceled when entering ConnectedState
+ verifySafemodeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+
getChildSessionCallback().onClosed();
mTestLooper.dispatchAll();
assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+
+ // Since network never validated, verify mSafemodeTimeoutAlarm not canceled
+ verifyNoMoreInteractions(mSafemodeTimeoutAlarm);
}
@Test
public void testIkeSessionClosedTriggersDisconnect() throws Exception {
+ // Verify scheduled but not canceled when entering ConnectedState
+ verifySafemodeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+
getIkeSessionCallback().onClosed();
mTestLooper.dispatchAll();
assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState());
verify(mIkeSession).close();
- verifyTeardownTimeoutAlarmAndGetCallback(true /* expectCanceled */);
+
+ // Since network never validated, verify mSafemodeTimeoutAlarm not canceled
+ verifyNoMoreInteractions(mSafemodeTimeoutAlarm);
}
}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
index 760379d6649d..07282c920088 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
@@ -106,4 +106,9 @@ public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectio
verify(mIkeSession).close();
verifyTeardownTimeoutAlarmAndGetCallback(true /* expectCanceled */);
}
+
+ @Test
+ public void testSafemodeTimeoutNotifiesCallback() {
+ verifySafemodeTimeoutNotifiesCallback(mGatewayConnection.mConnectingState);
+ }
}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
index 1a1787ac19d9..49ce54d4f684 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
@@ -48,7 +48,8 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect
.createIpSecTunnelInterface(
DUMMY_ADDR, DUMMY_ADDR, TEST_UNDERLYING_NETWORK_RECORD_1.network);
mGatewayConnection.setTunnelInterface(tunnelIface);
- mGatewayConnection.transitionTo(mGatewayConnection.mDisconnectedState);
+
+ // Don't need to transition to DisconnectedState because it is the starting state
mTestLooper.dispatchAll();
}
@@ -78,6 +79,7 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect
mTestLooper.dispatchAll();
assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState());
+ verifySafemodeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
}
@Test
@@ -98,5 +100,6 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect
assertNull(mGatewayConnection.getCurrentState());
verify(mIpSecSvc).deleteTunnelInterface(eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), any());
+ verifySafemodeTimeoutAlarmAndGetCallback(true /* expectCanceled */);
}
}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java
index b09f3a008c29..22eab2a1aa65 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java
@@ -80,4 +80,9 @@ public class VcnGatewayConnectionDisconnectingStateTest extends VcnGatewayConnec
assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */);
}
+
+ @Test
+ public void testSafemodeTimeoutNotifiesCallback() {
+ verifySafemodeTimeoutNotifiesCallback(mGatewayConnection.mDisconnectingState);
+ }
}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
index d37e92f661cc..6c2607586629 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
@@ -91,4 +91,9 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect
assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState());
verifyRetryTimeoutAlarmAndGetCallback(mFirstRetryInterval, true /* expectCanceled */);
}
+
+ @Test
+ public void testSafemodeTimeoutNotifiesCallback() {
+ verifySafemodeTimeoutNotifiesCallback(mGatewayConnection.mRetryTimeoutState);
+ }
}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
index 0b44e03a5e5a..ac9ec0663df2 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -20,6 +20,7 @@ import static com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkR
import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession;
import static com.android.server.vcn.VcnTestUtils.setupIpSecManager;
+import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.atLeastOnce;
@@ -50,6 +51,7 @@ import android.os.ParcelUuid;
import android.os.PowerManager;
import android.os.test.TestLooper;
+import com.android.internal.util.State;
import com.android.internal.util.WakeupMessage;
import com.android.server.IpSecService;
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
@@ -108,6 +110,7 @@ public class VcnGatewayConnectionTestBase {
@NonNull protected final WakeupMessage mTeardownTimeoutAlarm;
@NonNull protected final WakeupMessage mDisconnectRequestAlarm;
@NonNull protected final WakeupMessage mRetryTimeoutAlarm;
+ @NonNull protected final WakeupMessage mSafemodeTimeoutAlarm;
@NonNull protected final IpSecService mIpSecSvc;
@NonNull protected final ConnectivityManager mConnMgr;
@@ -128,6 +131,7 @@ public class VcnGatewayConnectionTestBase {
mTeardownTimeoutAlarm = mock(WakeupMessage.class);
mDisconnectRequestAlarm = mock(WakeupMessage.class);
mRetryTimeoutAlarm = mock(WakeupMessage.class);
+ mSafemodeTimeoutAlarm = mock(WakeupMessage.class);
mIpSecSvc = mock(IpSecService.class);
setupIpSecManager(mContext, mIpSecSvc);
@@ -150,6 +154,7 @@ public class VcnGatewayConnectionTestBase {
setUpWakeupMessage(mTeardownTimeoutAlarm, VcnGatewayConnection.TEARDOWN_TIMEOUT_ALARM);
setUpWakeupMessage(mDisconnectRequestAlarm, VcnGatewayConnection.DISCONNECT_REQUEST_ALARM);
setUpWakeupMessage(mRetryTimeoutAlarm, VcnGatewayConnection.RETRY_TIMEOUT_ALARM);
+ setUpWakeupMessage(mSafemodeTimeoutAlarm, VcnGatewayConnection.SAFEMODE_TIMEOUT_ALARM);
doReturn(ELAPSED_REAL_TIME).when(mDeps).getElapsedRealTime();
}
@@ -253,4 +258,24 @@ public class VcnGatewayConnectionTestBase {
delayInMillis,
expectCanceled);
}
+
+ protected Runnable verifySafemodeTimeoutAlarmAndGetCallback(boolean expectCanceled) {
+ return verifyWakeupMessageSetUpAndGetCallback(
+ VcnGatewayConnection.SAFEMODE_TIMEOUT_ALARM,
+ mSafemodeTimeoutAlarm,
+ TimeUnit.SECONDS.toMillis(VcnGatewayConnection.SAFEMODE_TIMEOUT_SECONDS),
+ expectCanceled);
+ }
+
+ protected void verifySafemodeTimeoutNotifiesCallback(@NonNull State expectedState) {
+ // Safemode timer starts when VcnGatewayConnection exits DisconnectedState (the initial
+ // state)
+ final Runnable delayedEvent =
+ verifySafemodeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+ delayedEvent.run();
+ mTestLooper.dispatchAll();
+
+ verify(mGatewayStatusCallback).onEnteredSafemode();
+ assertEquals(expectedState, mGatewayConnection.getCurrentState());
+ }
}