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

Commit 1170a0fb authored by chiachangwang's avatar chiachangwang
Browse files

Update longLivedTcpConnectionsExpensive value in VpnTransportInfo

The longLivedTcpConnectionsExpensive value relies on the keepalive
value, so the Vpn should send network capabilities update to renew
the VpnTransportInfo. The applications that may bypass VPN based
on the value could update with it accordingly.

The VpnTransportInfo should be recreated when
1. The NeworkAgent is created
2. The underlying network of the VPN network is updated
3. The carrierconfig is changed

The NetworkCapabilities may be updated more frequently than these
3 events. But the others does not affect the keepalive value so
it's fine to used the TransportInfo from existing
NetworkCapabilities.

Bug: 273422889
Test: atest FrameworksNetTests
Change-Id: Ia1a124fc06d2d882eb154f24a75493ad0a308a78
parent ec59bee3
Loading
Loading
Loading
Loading
+65 −19
Original line number Diff line number Diff line
@@ -270,6 +270,13 @@ public class Vpn {
    @VisibleForTesting
    static final int DEFAULT_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT = 5 * 60;

    /**
     * Default keepalive value to consider long-lived TCP connections are expensive on the
     * VPN network from battery usage point of view.
     * TODO: consider reading from setting.
     */
    @VisibleForTesting
    static final int DEFAULT_LONG_LIVED_TCP_CONNS_EXPENSIVE_TIMEOUT_SEC = 60;
    /**
     *  Prefer using {@link IkeSessionParams.ESP_IP_VERSION_AUTO} and
     *  {@link IkeSessionParams.ESP_ENCAP_TYPE_AUTO} for ESP packets.
@@ -1670,9 +1677,12 @@ public class Vpn {
        capsBuilder.setUids(createUserAndRestrictedProfilesRanges(mUserId,
                mConfig.allowedApplications, mConfig.disallowedApplications));

        capsBuilder.setTransportInfo(
                new VpnTransportInfo(getActiveVpnType(), mConfig.session, mConfig.allowBypass,
                        false /* longLivedTcpConnectionsExpensive */));
        final boolean expensive = areLongLivedTcpConnectionsExpensive(mVpnRunner);
        capsBuilder.setTransportInfo(new VpnTransportInfo(
                getActiveVpnType(),
                mConfig.session,
                mConfig.allowBypass,
                expensive));

        // Only apps targeting Q and above can explicitly declare themselves as metered.
        // These VPNs are assumed metered unless they state otherwise.
@@ -1704,6 +1714,17 @@ public class Vpn {
        updateState(DetailedState.CONNECTED, "agentConnect");
    }

    private static boolean areLongLivedTcpConnectionsExpensive(@NonNull VpnRunner runner) {
        if (!(runner instanceof IkeV2VpnRunner)) return false;

        final int delay = ((IkeV2VpnRunner) runner).getOrGuessKeepaliveDelaySeconds();
        return areLongLivedTcpConnectionsExpensive(delay);
    }

    private static boolean areLongLivedTcpConnectionsExpensive(int keepaliveDelaySec) {
        return keepaliveDelaySec < DEFAULT_LONG_LIVED_TCP_CONNS_EXPENSIVE_TIMEOUT_SEC;
    }

    private boolean canHaveRestrictedProfile(int userId) {
        final long token = Binder.clearCallingIdentity();
        try {
@@ -2988,10 +3009,8 @@ public class Vpn {
                            // Ignore stale runner.
                            if (mVpnRunner != Vpn.IkeV2VpnRunner.this) return;

                            maybeMigrateIkeSession(mActiveNetwork);
                            maybeMigrateIkeSessionAndUpdateVpnTransportInfo(mActiveNetwork);
                        }
                        // TODO: update the longLivedTcpConnectionsExpensive value in the
                        //  networkcapabilities of the VPN network.
                    }
        };

@@ -3442,7 +3461,7 @@ public class Vpn {
                return;
            }

            if (maybeMigrateIkeSession(underlyingNetwork)) return;
            if (maybeMigrateIkeSessionAndUpdateVpnTransportInfo(underlyingNetwork)) return;

            startIkeSession(underlyingNetwork);
        }
@@ -3549,7 +3568,43 @@ public class Vpn {
            return new CarrierConfigInfo(mccMnc, natKeepalive, encapType, ipVersion);
        }

        boolean maybeMigrateIkeSession(@NonNull Network underlyingNetwork) {
        private int getOrGuessKeepaliveDelaySeconds() {
            if (mProfile.isAutomaticNattKeepaliveTimerEnabled()) {
                return guessNattKeepaliveTimerForNetwork();
            } else if (mProfile.getIkeTunnelConnectionParams() != null) {
                return mProfile.getIkeTunnelConnectionParams()
                        .getIkeSessionParams().getNattKeepAliveDelaySeconds();
            }
            return DEFAULT_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT;
        }

        boolean maybeMigrateIkeSessionAndUpdateVpnTransportInfo(
                @NonNull Network underlyingNetwork) {
            final int keepaliveDelaySec = getOrGuessKeepaliveDelaySeconds();
            final boolean migrated = maybeMigrateIkeSession(underlyingNetwork, keepaliveDelaySec);
            if (migrated) {
                updateVpnTransportInfoAndNetCap(keepaliveDelaySec);
            }
            return migrated;
        }

        public void updateVpnTransportInfoAndNetCap(int keepaliveDelaySec) {
            final VpnTransportInfo info = new VpnTransportInfo(
                    getActiveVpnType(),
                    mConfig.session,
                    mConfig.allowBypass,
                    areLongLivedTcpConnectionsExpensive(keepaliveDelaySec));
            final boolean ncUpdateRequired = !info.equals(mNetworkCapabilities.getTransportInfo());
            if (ncUpdateRequired) {
                mNetworkCapabilities = new NetworkCapabilities.Builder(mNetworkCapabilities)
                        .setTransportInfo(info)
                        .build();
                doSendNetworkCapabilities(mNetworkAgent, mNetworkCapabilities);
            }
        }

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

            // IKE session can schedule a migration event only when IKE AUTH is finished
@@ -3574,15 +3629,6 @@ public class Vpn {
                encapType = ESP_ENCAP_TYPE_AUTO;
            }

            final int keepaliveDelaySeconds;
            if (mProfile.isAutomaticNattKeepaliveTimerEnabled()) {
                keepaliveDelaySeconds = guessNattKeepaliveTimerForNetwork();
            } else if (mProfile.getIkeTunnelConnectionParams() != null) {
                keepaliveDelaySeconds = mProfile.getIkeTunnelConnectionParams()
                        .getIkeSessionParams().getNattKeepAliveDelaySeconds();
            } else {
                keepaliveDelaySeconds = DEFAULT_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT;
            }
            mSession.setNetwork(underlyingNetwork, ipVersion, encapType, keepaliveDelaySeconds);
            return true;
        }
@@ -3663,7 +3709,7 @@ public class Vpn {
                startOrMigrateIkeSession(mActiveNetwork);
            } else if (!nc.getSubscriptionIds().equals(oldNc.getSubscriptionIds())) {
                // Renew carrierConfig values.
                maybeMigrateIkeSession(mActiveNetwork);
                maybeMigrateIkeSessionAndUpdateVpnTransportInfo(mActiveNetwork);
            }
        }

@@ -3691,7 +3737,7 @@ public class Vpn {
                        Log.d(TAG, "Data stall suspected");

                        // Trigger MOBIKE.
                        maybeMigrateIkeSession(mActiveNetwork);
                        maybeMigrateIkeSessionAndUpdateVpnTransportInfo(mActiveNetwork);
                        mDataStallSuspected = true;
                    }
                }