Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 80b23ae4 authored by Chiachang Wang's avatar Chiachang Wang Committed by Automerger Merge Worker
Browse files

Merge "Reset Ike session if stall is not recovered by MOBIKE" am: 246fc31e

parents 16958524 246fc31e
Loading
Loading
Loading
Loading
+95 −8
Original line number Diff line number Diff line
@@ -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);
            }
        }
    }

    /**