Merge "Reset Ike session if stall is not recovered by MOBIKE"

This commit is contained in:
Chiachang Wang
2022-10-27 05:13:45 +00:00
committed by Gerrit Code Review

View File

@@ -79,6 +79,7 @@ import android.net.NetworkScore;
import android.net.RouteInfo;
import android.net.UidRangeParcel;
import android.net.UnderlyingNetworkInfo;
import android.net.Uri;
import android.net.VpnManager;
import android.net.VpnProfileState;
import android.net.VpnService;
@@ -225,6 +226,16 @@ 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
* counter is reset on successful validation only.
*
* <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};
/**
* The initial token value of IKE session.
*/
@@ -271,6 +282,7 @@ public class Vpn {
private final UserManager mUserManager;
private final VpnProfileStore mVpnProfileStore;
protected boolean mDataStallSuspected = false;
@VisibleForTesting
VpnProfileStore getVpnProfileStore() {
@@ -522,10 +534,28 @@ public class Vpn {
@NonNull LinkProperties lp,
@NonNull NetworkScore score,
@NonNull NetworkAgentConfig config,
@Nullable NetworkProvider provider) {
@Nullable NetworkProvider provider,
@Nullable ValidationStatusCallback callback) {
return new VpnNetworkAgentWrapper(
context, looper, logTag, nc, lp, score, config, provider);
context, looper, logTag, nc, lp, score, config, provider, callback);
}
/**
* Get the length of time to wait before resetting the ike session when a data stall is
* suspected.
*/
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];
} else {
return DATA_STALL_RESET_DELAYS_SEC[count];
}
}
}
@VisibleForTesting
interface ValidationStatusCallback {
void onValidationStatus(int status);
}
public Vpn(Looper looper, Context context, INetworkManagementService netService, INetd netd,
@@ -1460,6 +1490,11 @@ public class Vpn {
@GuardedBy("this")
private void agentConnect() {
agentConnect(null /* validationCallback */);
}
@GuardedBy("this")
private void agentConnect(@Nullable ValidationStatusCallback validationCallback) {
LinkProperties lp = makeLinkProperties();
// VPN either provide a default route (IPv4 or IPv6 or both), or they are a split tunnel
@@ -1507,7 +1542,7 @@ public class Vpn {
mNetworkAgent = mDeps.newNetworkAgent(mContext, mLooper, NETWORKTYPE /* logtag */,
mNetworkCapabilities, lp,
new NetworkScore.Builder().setLegacyInt(VPN_DEFAULT_SCORE).build(),
networkAgentConfig, mNetworkProvider);
networkAgentConfig, mNetworkProvider, validationCallback);
final long token = Binder.clearCallingIdentity();
try {
mNetworkAgent.register();
@@ -2723,7 +2758,7 @@ public class Vpn {
@Nullable private ScheduledFuture<?> mScheduledHandleNetworkLostFuture;
@Nullable private ScheduledFuture<?> mScheduledHandleRetryIkeSessionFuture;
@Nullable private ScheduledFuture<?> mScheduledHandleDataStallFuture;
/** Signal to ensure shutdown is honored even if a new Network is connected. */
private boolean mIsRunning = true;
@@ -2749,6 +2784,14 @@ public class Vpn {
// mMobikeEnabled can only be updated after IKE AUTH is finished.
private boolean mMobikeEnabled = false;
/**
* The number of attempts to reset the IKE session since the last successful connection.
*
* <p>This variable controls the retry delay, and is reset when the VPN pass network
* validation.
*/
private int mDataStallRetryCount = 0;
/**
* The number of attempts since the last successful connection.
*
@@ -2931,7 +2974,7 @@ public class Vpn {
if (isSettingsVpnLocked()) {
prepareStatusIntent();
}
agentConnect();
agentConnect(this::onValidationStatus);
return; // Link properties are already sent.
} else {
// Underlying networks also set in agentConnect()
@@ -3200,18 +3243,52 @@ public class Vpn {
// Ignore stale runner.
if (mVpnRunner != Vpn.IkeV2VpnRunner.this) return;
// Handle the report only for current VPN network.
// 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())) {
&& mNetworkAgent.getNetwork().equals(report.getNetwork())
&& !mDataStallSuspected) {
Log.d(TAG, "Data stall suspected");
// Trigger MOBIKE.
maybeMigrateIkeSession(mActiveNetwork);
mDataStallSuspected = true;
}
}
}
}
public void onValidationStatus(int status) {
if (status == NetworkAgent.VALIDATION_STATUS_VALID) {
// No data stall now. Reset it.
mExecutor.execute(() -> {
mDataStallSuspected = false;
mDataStallRetryCount = 0;
if (mScheduledHandleDataStallFuture != null) {
Log.d(TAG, "Recovered from stall. Cancel pending reset action.");
mScheduledHandleDataStallFuture.cancel(false /* mayInterruptIfRunning */);
mScheduledHandleDataStallFuture = null;
}
});
} else {
// Skip other invalid status if the scheduled recovery exists.
if (mScheduledHandleDataStallFuture != null) return;
mScheduledHandleDataStallFuture = mExecutor.schedule(() -> {
if (mDataStallSuspected) {
Log.d(TAG, "Reset session to recover stalled network");
// This will reset old state if it exists.
startIkeSession(mActiveNetwork);
}
// Reset mScheduledHandleDataStallFuture since it's already run on executor
// thread.
mScheduledHandleDataStallFuture = null;
}, mDeps.getDataStallResetSessionSeconds(mDataStallRetryCount++), TimeUnit.SECONDS);
}
}
/**
* Handles loss of the default underlying network
*
@@ -4339,6 +4416,7 @@ public class Vpn {
// un-finalized.
@VisibleForTesting
public static class VpnNetworkAgentWrapper extends NetworkAgent {
private final ValidationStatusCallback mCallback;
/** Create an VpnNetworkAgentWrapper */
public VpnNetworkAgentWrapper(
@NonNull Context context,
@@ -4348,8 +4426,10 @@ public class Vpn {
@NonNull LinkProperties lp,
@NonNull NetworkScore score,
@NonNull NetworkAgentConfig config,
@Nullable NetworkProvider provider) {
@Nullable NetworkProvider provider,
@Nullable ValidationStatusCallback callback) {
super(context, looper, logTag, nc, lp, score, config, provider);
mCallback = callback;
}
/** Update the LinkProperties */
@@ -4371,6 +4451,13 @@ public class Vpn {
public void onNetworkUnwanted() {
// We are user controlled, not driven by NetworkRequest.
}
@Override
public void onValidationStatus(int status, Uri redirectUri) {
if (mCallback != null) {
mCallback.onValidationStatus(status);
}
}
}
/**