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

Commit 82655efb authored by chiachangwang's avatar chiachangwang
Browse files

Perform MOBIKE when data stall is suspected

Trigger MOBIKE when data stall happens in VPN network.

VPN tunnels may break as a result of the NAT mapping expiring,
which may be able to be corrected via a MOBIKE event.

Bug: 238692379
Test: atest FrameworksNetTests
Change-Id: I3f677e6b65146af67a286d6d654f30b06134d31d
parent cb82e0cb
Loading
Loading
Loading
Loading
+59 −14
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.Manifest.permission.CONTROL_VPN;
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_VPN;
import static android.net.RouteInfo.RTN_THROW;
import static android.net.RouteInfo.RTN_UNREACHABLE;
import static android.net.VpnManager.NOTIFICATION_CHANNEL_VPN;
@@ -51,6 +52,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.net.ConnectivityDiagnosticsManager;
import android.net.ConnectivityManager;
import android.net.DnsResolver;
import android.net.INetd;
@@ -234,6 +236,7 @@ public class Vpn {
    private final Context mContext;
    private final ConnectivityManager mConnectivityManager;
    private final AppOpsManager mAppOpsManager;
    private final ConnectivityDiagnosticsManager mConnectivityDiagnosticsManager;
    // The context is for specific user which is created from mUserId
    private final Context mUserIdContext;
    @VisibleForTesting final Dependencies mDeps;
@@ -549,6 +552,8 @@ public class Vpn {
        mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
        mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
        mUserIdContext = context.createContextAsUser(UserHandle.of(userId), 0 /* flags */);
        mConnectivityDiagnosticsManager =
                mContext.getSystemService(ConnectivityDiagnosticsManager.class);
        mDeps = deps;
        mNms = netService;
        mNetd = netd;
@@ -2739,6 +2744,7 @@ 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;
@@ -2797,6 +2803,15 @@ 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) {
@@ -3066,22 +3081,28 @@ public class Vpn {
                return;
            }

            try {
                if (mSession != null && mMobikeEnabled) {
            if (maybeMigrateIkeSession(underlyingNetwork)) return;

            startIkeSession(underlyingNetwork);
        }

        boolean maybeMigrateIkeSession(@NonNull Network underlyingNetwork) {
            if (mSession == null || !mMobikeEnabled) return false;

            // IKE session can schedule a migration event only when IKE AUTH is finished
            // and mMobikeEnabled is true.
                    Log.d(
                            TAG,
                            "Migrate IKE Session with token "
            Log.d(TAG, "Migrate IKE Session with token "
                    + mCurrentToken
                    + " to network "
                    + underlyingNetwork);
            mSession.setNetwork(underlyingNetwork);
                    return;
            return true;
        }

        private void startIkeSession(@NonNull Network underlyingNetwork) {
            Log.d(TAG, "Start new IKE session on network " + underlyingNetwork);

            try {
                // Clear mInterface to prevent Ikev2VpnRunner being cleared when
                // interfaceRemoved() is called.
                synchronized (Vpn.this) {
@@ -3169,6 +3190,28 @@ public class Vpn {
            mUnderlyingLinkProperties = lp;
        }

        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 (mNetworkAgent != null
                            && mNetworkAgent.getNetwork().equals(report.getNetwork())) {
                        Log.d(TAG, "Data stall suspected");

                        // Trigger MOBIKE.
                        maybeMigrateIkeSession(mActiveNetwork);
                    }
                }
            }
        }

        /**
         * Handles loss of the default underlying network
         *
@@ -3463,6 +3506,8 @@ public class Vpn {
            resetIkeState();

            mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
            mConnectivityDiagnosticsManager.unregisterConnectivityDiagnosticsCallback(
                    mDiagnosticsCallback);

            mExecutor.shutdown();
        }