diff options
| author | 2022-10-27 06:15:13 +0000 | |
|---|---|---|
| committer | 2022-10-27 06:15:13 +0000 | |
| commit | 284af510d0e636b92b52cb2b67423de5bea45025 (patch) | |
| tree | d003d76528b2bc599a1d11353ed73e01171e58f0 | |
| parent | 7938926336bd438d993f4a5a8edd4b5f4abe3aeb (diff) | |
| parent | 80b23ae4a915927c872f2cab258c760c579d766f (diff) | |
Merge "Reset Ike session if stall is not recovered by MOBIKE" am: 246fc31ef5 am: 80b23ae4a9
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/2159077
Change-Id: I839943359bbad7136d1a56672a305e8cc23ea9bd
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
| -rw-r--r-- | services/core/java/com/android/server/connectivity/Vpn.java | 103 |
1 files changed, 95 insertions, 8 deletions
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 6795b6b4158d..45b0f0a6d04a 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -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; @@ -226,6 +227,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. */ private static final int STARTING_TOKEN = -1; @@ -271,6 +282,7 @@ public class Vpn { private final UserManager mUserManager; private final VpnProfileStore mVpnProfileStore; + protected boolean mDataStallSuspected = false; @VisibleForTesting VpnProfileStore getVpnProfileStore() { @@ -522,12 +534,30 @@ 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, @UserIdInt int userId, VpnProfileStore vpnProfileStore) { this(looper, context, new Dependencies(), netService, netd, userId, vpnProfileStore, @@ -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; @@ -2750,6 +2785,14 @@ public class Vpn { 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. * * <p>This variable controls the retry delay, and is reset when a new IKE session is @@ -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); + } + } } /** |