diff options
| -rw-r--r-- | services/core/java/com/android/server/connectivity/Vpn.java | 105 |
1 files changed, 102 insertions, 3 deletions
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 1ce917cb7841..c39b4ffcf352 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -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_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static android.net.RouteInfo.RTN_THROW; import static android.net.RouteInfo.RTN_UNREACHABLE; @@ -29,6 +30,7 @@ import static android.net.ipsec.ike.IkeSessionParams.ESP_ENCAP_TYPE_AUTO; import static android.net.ipsec.ike.IkeSessionParams.ESP_IP_VERSION_AUTO; import static android.os.PowerWhitelistManager.REASON_VPN; import static android.os.UserHandle.PER_USER_RANGE; +import static android.telephony.CarrierConfigManager.KEY_MIN_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT; import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU; import static com.android.server.vcn.util.PersistableBundleUtils.STRING_DESERIALIZER; @@ -79,7 +81,9 @@ import android.net.NetworkInfo.DetailedState; import android.net.NetworkProvider; import android.net.NetworkRequest; import android.net.NetworkScore; +import android.net.NetworkSpecifier; import android.net.RouteInfo; +import android.net.TelephonyNetworkSpecifier; import android.net.UidRangeParcel; import android.net.UnderlyingNetworkInfo; import android.net.Uri; @@ -127,12 +131,16 @@ import android.security.keystore.KeyProperties; import android.system.keystore2.Domain; import android.system.keystore2.KeyDescriptor; import android.system.keystore2.KeyPermission; +import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.ArraySet; import android.util.IndentingPrintWriter; import android.util.LocalLog; import android.util.Log; import android.util.Range; +import android.util.SparseArray; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; @@ -268,6 +276,10 @@ public class Vpn { private final ConnectivityManager mConnectivityManager; private final AppOpsManager mAppOpsManager; private final ConnectivityDiagnosticsManager mConnectivityDiagnosticsManager; + private final TelephonyManager mTelephonyManager; + private final CarrierConfigManager mCarrierConfigManager; + private final SubscriptionManager mSubscriptionManager; + // The context is for specific user which is created from mUserId private final Context mUserIdContext; @VisibleForTesting final Dependencies mDeps; @@ -314,6 +326,14 @@ public class Vpn { private final LocalLog mVpnManagerEvents = new LocalLog(MAX_EVENTS_LOGS); /** + * Cached Map of <subscription ID, keepalive delay ms> since retrieving the PersistableBundle + * and the target value from CarrierConfigManager is somewhat expensive as it has hundreds of + * fields. This cache is cleared when the carrier config changes to ensure data freshness. + */ + @GuardedBy("this") + private final SparseArray<Integer> mCachedKeepalivePerSubId = new SparseArray<>(); + + /** * Whether to keep the connection active after rebooting, or upgrading or reinstalling. This * only applies to {@link VpnService} connections. */ @@ -626,6 +646,10 @@ public class Vpn { mUserIdContext = context.createContextAsUser(UserHandle.of(userId), 0 /* flags */); mConnectivityDiagnosticsManager = mContext.getSystemService(ConnectivityDiagnosticsManager.class); + mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class); + mTelephonyManager = mContext.getSystemService(TelephonyManager.class); + mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class); + mDeps = deps; mNms = netService; mNetd = netd; @@ -2893,6 +2917,24 @@ public class Vpn { */ private int mRetryCount = 0; + private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener = + new CarrierConfigManager.CarrierConfigChangeListener() { + @Override + public void onCarrierConfigChanged(int slotIndex, int subId, int carrierId, + int specificCarrierId) { + synchronized (Vpn.this) { + mCachedKeepalivePerSubId.remove(subId); + + // Ignore stale runner. + if (mVpnRunner != Vpn.IkeV2VpnRunner.this) return; + + maybeMigrateIkeSession(mActiveNetwork); + } + // TODO: update the longLivedTcpConnectionsExpensive value in the + // networkcapabilities of the VPN network. + } + }; + IkeV2VpnRunner( @NonNull Ikev2VpnProfile profile, @NonNull ScheduledThreadPoolExecutor executor) { super(TAG); @@ -2918,6 +2960,9 @@ public class Vpn { setVpnNetworkPreference(mSessionKey, createUserAndRestrictedProfilesRanges(mUserId, mConfig.allowedApplications, mConfig.disallowedApplications)); + + mCarrierConfigManager.registerCarrierConfigChangeListener(mExecutor, + mCarrierConfigChangeListener); } @Override @@ -3356,9 +3401,36 @@ public class Vpn { } private int guessNattKeepaliveTimerForNetwork() { - // TODO : guess the keepalive delay based on carrier if auto keepalive timer is - // enabled - return AUTOMATIC_KEEPALIVE_DELAY_SECONDS; + final int subId = getCellSubIdForNetworkCapabilities(mUnderlyingNetworkCapabilities); + if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + Log.d(TAG, "Underlying network is not a cellular network"); + return AUTOMATIC_KEEPALIVE_DELAY_SECONDS; + } + + synchronized (Vpn.this) { + if (mCachedKeepalivePerSubId.contains(subId)) { + Log.d(TAG, "Get cached keepalive config"); + return mCachedKeepalivePerSubId.get(subId); + } + + final TelephonyManager perSubTm = mTelephonyManager.createForSubscriptionId(subId); + if (perSubTm.getSimApplicationState() != TelephonyManager.SIM_STATE_LOADED) { + Log.d(TAG, "SIM card is not ready on sub " + subId); + return AUTOMATIC_KEEPALIVE_DELAY_SECONDS; + } + + final PersistableBundle carrierConfig = + mCarrierConfigManager.getConfigForSubId(subId); + if (!CarrierConfigManager.isConfigForIdentifiedCarrier(carrierConfig)) { + return AUTOMATIC_KEEPALIVE_DELAY_SECONDS; + } + + final int natKeepalive = + carrierConfig.getInt(KEY_MIN_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT); + mCachedKeepalivePerSubId.put(subId, natKeepalive); + Log.d(TAG, "Get customized keepalive=" + natKeepalive); + return natKeepalive; + } } boolean maybeMigrateIkeSession(@NonNull Network underlyingNetwork) { @@ -3456,7 +3528,15 @@ public class Vpn { /** Called when the NetworkCapabilities of underlying network is changed */ public void onDefaultNetworkCapabilitiesChanged(@NonNull NetworkCapabilities nc) { + final NetworkCapabilities oldNc = mUnderlyingNetworkCapabilities; mUnderlyingNetworkCapabilities = nc; + // The oldNc may be null when it's not assigned yet. + final boolean subIdChanged = + (oldNc == null) || !nc.getSubscriptionIds().equals(oldNc.getSubscriptionIds()); + // Update carrierConfig. + if (subIdChanged) { + maybeMigrateIkeSession(mActiveNetwork); + } } /** Called when the LinkProperties of underlying network is changed */ @@ -3812,6 +3892,8 @@ public class Vpn { resetIkeState(); + mCarrierConfigManager.unregisterCarrierConfigChangeListener( + mCarrierConfigChangeListener); mConnectivityManager.unregisterNetworkCallback(mNetworkCallback); mConnectivityDiagnosticsManager.unregisterConnectivityDiagnosticsCallback( mDiagnosticsCallback); @@ -4804,6 +4886,8 @@ public class Vpn { pw.println("Reset session scheduled"); } } + pw.println("mCachedKeepalivePerSubId=" + mCachedKeepalivePerSubId); + pw.println("mUnderlyNetworkChanges (most recent first):"); pw.increaseIndent(); mUnderlyNetworkChanges.reverseDump(pw); @@ -4815,4 +4899,19 @@ public class Vpn { pw.decreaseIndent(); } } + + private static int getCellSubIdForNetworkCapabilities(@Nullable NetworkCapabilities nc) { + if (nc == null) return SubscriptionManager.INVALID_SUBSCRIPTION_ID; + + if (!nc.hasTransport(TRANSPORT_CELLULAR)) { + return SubscriptionManager.INVALID_SUBSCRIPTION_ID; + } + + final NetworkSpecifier specifier = nc.getNetworkSpecifier(); + if (specifier instanceof TelephonyNetworkSpecifier) { + return ((TelephonyNetworkSpecifier) specifier).getSubscriptionId(); + } + + return SubscriptionManager.INVALID_SUBSCRIPTION_ID; + } } |