Perform VPN data stall recovery on unvalidated VPN network am: b4f300d70d
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/2643292 Change-Id: I2d84c81a4444bf65b309541f7716bd8d0dd6a568 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -22,7 +22,6 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||
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 @@ public class Vpn {
|
||||
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.
|
||||
*/
|
||||
@@ -392,7 +398,6 @@ public class Vpn {
|
||||
private final UserManager mUserManager;
|
||||
|
||||
private final VpnProfileStore mVpnProfileStore;
|
||||
protected boolean mDataStallSuspected = false;
|
||||
|
||||
@VisibleForTesting
|
||||
VpnProfileStore getVpnProfileStore() {
|
||||
@@ -685,14 +690,14 @@ public class Vpn {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3044,7 +3049,6 @@ public class Vpn {
|
||||
|
||||
@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;
|
||||
@@ -3055,7 +3059,7 @@ public class Vpn {
|
||||
* <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.
|
||||
@@ -3136,15 +3140,6 @@ public class Vpn {
|
||||
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) {
|
||||
@@ -3875,39 +3870,12 @@ public class Vpn {
|
||||
}
|
||||
}
|
||||
|
||||
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 */);
|
||||
@@ -3918,8 +3886,21 @@ public class Vpn {
|
||||
// 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);
|
||||
@@ -3928,7 +3909,9 @@ public class Vpn {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4231,8 +4214,6 @@ public class Vpn {
|
||||
mCarrierConfigManager.unregisterCarrierConfigChangeListener(
|
||||
mCarrierConfigChangeListener);
|
||||
mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
|
||||
mConnectivityDiagnosticsManager.unregisterConnectivityDiagnosticsCallback(
|
||||
mDiagnosticsCallback);
|
||||
clearVpnNetworkPreference(mSessionKey);
|
||||
|
||||
mExecutor.shutdown();
|
||||
@@ -5216,7 +5197,7 @@ public class Vpn {
|
||||
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");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user