Merge "Perform VPN data stall recovery on unvalidated VPN network" into udc-d1-dev
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index c1df335..e3262cf 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -22,7 +22,6 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.RouteInfo.RTN_THROW;
import static android.net.RouteInfo.RTN_UNREACHABLE;
import static android.net.VpnManager.NOTIFICATION_CHANNEL_VPN;
@@ -280,15 +279,22 @@
private static final int VPN_DEFAULT_SCORE = 101;
/**
- * The reset session timer for data stall. If a session has not successfully revalidated after
- * the delay, the session will be torn down and restarted in an attempt to recover. Delay
+ * The recovery timer for data stall. If a session has not successfully revalidated after
+ * the delay, the session will perform MOBIKE or be restarted in an attempt to recover. Delay
* counter is reset on successful validation only.
*
+ * <p>The first {@code MOBIKE_RECOVERY_ATTEMPT} timers are used for performing MOBIKE.
+ * System will perform session reset for the remaining timers.
* <p>If retries have exceeded the length of this array, the last entry in the array will be
* used as a repeating interval.
*/
- private static final long[] DATA_STALL_RESET_DELAYS_SEC = {30L, 60L, 120L, 240L, 480L, 960L};
-
+ // TODO: use ms instead to speed up the test.
+ private static final long[] DATA_STALL_RECOVERY_DELAYS_SEC =
+ {1L, 5L, 30L, 60L, 120L, 240L, 480L, 960L};
+ /**
+ * Maximum attempts to perform MOBIKE when the network is bad.
+ */
+ private static final int MAX_MOBIKE_RECOVERY_ATTEMPT = 2;
/**
* The initial token value of IKE session.
*/
@@ -393,7 +399,6 @@
private final UserManager mUserManager;
private final VpnProfileStore mVpnProfileStore;
- protected boolean mDataStallSuspected = false;
@VisibleForTesting
VpnProfileStore getVpnProfileStore() {
@@ -686,14 +691,14 @@
}
/**
- * Get the length of time to wait before resetting the ike session when a data stall is
- * suspected.
+ * Get the length of time to wait before perform data stall recovery when the validation
+ * result is bad.
*/
- public long getDataStallResetSessionSeconds(int count) {
- if (count >= DATA_STALL_RESET_DELAYS_SEC.length) {
- return DATA_STALL_RESET_DELAYS_SEC[DATA_STALL_RESET_DELAYS_SEC.length - 1];
+ public long getValidationFailRecoverySeconds(int count) {
+ if (count >= DATA_STALL_RECOVERY_DELAYS_SEC.length) {
+ return DATA_STALL_RECOVERY_DELAYS_SEC[DATA_STALL_RECOVERY_DELAYS_SEC.length - 1];
} else {
- return DATA_STALL_RESET_DELAYS_SEC[count];
+ return DATA_STALL_RECOVERY_DELAYS_SEC[count];
}
}
@@ -3052,7 +3057,6 @@
@Nullable private IkeSessionWrapper mSession;
@Nullable private IkeSessionConnectionInfo mIkeConnectionInfo;
- @Nullable private VpnConnectivityDiagnosticsCallback mDiagnosticsCallback;
// mMobikeEnabled can only be updated after IKE AUTH is finished.
private boolean mMobikeEnabled = false;
@@ -3063,7 +3067,7 @@
* <p>This variable controls the retry delay, and is reset when the VPN pass network
* validation.
*/
- private int mDataStallRetryCount = 0;
+ private int mValidationFailRetryCount = 0;
/**
* The number of attempts since the last successful connection.
@@ -3145,15 +3149,6 @@
mConnectivityManager.registerSystemDefaultNetworkCallback(mNetworkCallback,
new Handler(mLooper));
}
-
- // DiagnosticsCallback may return more than one alive VPNs, but VPN will filter based on
- // Network object.
- final NetworkRequest diagRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_VPN)
- .removeCapability(NET_CAPABILITY_NOT_VPN).build();
- mDiagnosticsCallback = new VpnConnectivityDiagnosticsCallback();
- mConnectivityDiagnosticsManager.registerConnectivityDiagnosticsCallback(
- diagRequest, mExecutor, mDiagnosticsCallback);
}
private boolean isActiveNetwork(@Nullable Network network) {
@@ -3887,39 +3882,12 @@
}
}
- class VpnConnectivityDiagnosticsCallback
- extends ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback {
- // The callback runs in the executor thread.
- @Override
- public void onDataStallSuspected(
- ConnectivityDiagnosticsManager.DataStallReport report) {
- synchronized (Vpn.this) {
- // Ignore stale runner.
- if (mVpnRunner != Vpn.IkeV2VpnRunner.this) return;
-
- // Handle the report only for current VPN network. If data stall is already
- // reported, ignoring the other reports. It means that the stall is not
- // recovered by MOBIKE and should be on the way to reset the ike session.
- if (mNetworkAgent != null
- && mNetworkAgent.getNetwork().equals(report.getNetwork())
- && !mDataStallSuspected) {
- Log.d(TAG, "Data stall suspected");
-
- // Trigger MOBIKE.
- maybeMigrateIkeSessionAndUpdateVpnTransportInfo(mActiveNetwork);
- mDataStallSuspected = true;
- }
- }
- }
- }
-
public void onValidationStatus(int status) {
mEventChanges.log("[Validation] validation status " + status);
if (status == NetworkAgent.VALIDATION_STATUS_VALID) {
// No data stall now. Reset it.
mExecutor.execute(() -> {
- mDataStallSuspected = false;
- mDataStallRetryCount = 0;
+ mValidationFailRetryCount = 0;
if (mScheduledHandleDataStallFuture != null) {
Log.d(TAG, "Recovered from stall. Cancel pending reset action.");
mScheduledHandleDataStallFuture.cancel(false /* mayInterruptIfRunning */);
@@ -3930,8 +3898,21 @@
// Skip other invalid status if the scheduled recovery exists.
if (mScheduledHandleDataStallFuture != null) return;
+ if (mValidationFailRetryCount < MAX_MOBIKE_RECOVERY_ATTEMPT) {
+ Log.d(TAG, "Validation failed");
+
+ // Trigger MOBIKE to recover first.
+ mExecutor.schedule(() -> {
+ maybeMigrateIkeSessionAndUpdateVpnTransportInfo(mActiveNetwork);
+ }, mDeps.getValidationFailRecoverySeconds(mValidationFailRetryCount++),
+ TimeUnit.SECONDS);
+ return;
+ }
+
+ // Data stall is not recovered by MOBIKE. Try to reset session to recover it.
mScheduledHandleDataStallFuture = mExecutor.schedule(() -> {
- if (mDataStallSuspected) {
+ // Only perform the recovery when the network is still bad.
+ if (mValidationFailRetryCount > 0) {
Log.d(TAG, "Reset session to recover stalled network");
// This will reset old state if it exists.
startIkeSession(mActiveNetwork);
@@ -3940,7 +3921,9 @@
// Reset mScheduledHandleDataStallFuture since it's already run on executor
// thread.
mScheduledHandleDataStallFuture = null;
- }, mDeps.getDataStallResetSessionSeconds(mDataStallRetryCount++), TimeUnit.SECONDS);
+ // TODO: compute the delay based on the last recovery timestamp
+ }, mDeps.getValidationFailRecoverySeconds(mValidationFailRetryCount++),
+ TimeUnit.SECONDS);
}
}
@@ -4243,8 +4226,6 @@
mCarrierConfigManager.unregisterCarrierConfigChangeListener(
mCarrierConfigChangeListener);
mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
- mConnectivityDiagnosticsManager.unregisterConnectivityDiagnosticsCallback(
- mDiagnosticsCallback);
clearVpnNetworkPreference(mSessionKey);
mExecutor.shutdown();
@@ -5231,7 +5212,7 @@
pw.println("MOBIKE " + (runner.mMobikeEnabled ? "enabled" : "disabled"));
pw.println("Profile: " + runner.mProfile);
pw.println("Token: " + runner.mCurrentToken);
- if (mDataStallSuspected) pw.println("Data stall suspected");
+ pw.println("Validation failed retry count:" + runner.mValidationFailRetryCount);
if (runner.mScheduledHandleDataStallFuture != null) {
pw.println("Reset session scheduled");
}