diff options
| author | 2024-10-02 22:00:37 +0000 | |
|---|---|---|
| committer | 2024-10-02 22:00:37 +0000 | |
| commit | a90ea9c8049e2672a8c1bafc06f0ffce47c99c4d (patch) | |
| tree | 0475779b1fe33824cdcdf5319836e3256df6b209 | |
| parent | 109eb2757e3e90fb3af22bf0c35984063f739dd3 (diff) | |
| parent | c595ed6ac9a319df9c1084f8943ee9f94b2e4c65 (diff) | |
Merge "Add VcnUtils to easily get WifiInfo and subId from NetworkCapabilities" into main am: 13ba8acf56 am: c595ed6ac9
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/3286259
Change-Id: I8e3302f83d9f1b2144dfb1700b165d1e5c053f55
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
| -rw-r--r-- | core/java/android/net/vcn/VcnTransportInfo.java | 43 | ||||
| -rw-r--r-- | core/java/android/net/vcn/VcnUtils.java | 97 | ||||
| -rw-r--r-- | tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java | 23 | ||||
| -rw-r--r-- | tests/vcn/java/android/net/vcn/VcnUtilsTest.java | 136 |
4 files changed, 299 insertions, 0 deletions
diff --git a/core/java/android/net/vcn/VcnTransportInfo.java b/core/java/android/net/vcn/VcnTransportInfo.java index f5469104be7f..1fc91eea3138 100644 --- a/core/java/android/net/vcn/VcnTransportInfo.java +++ b/core/java/android/net/vcn/VcnTransportInfo.java @@ -17,9 +17,11 @@ package android.net.vcn; import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS; +import static android.net.vcn.VcnGatewayConnectionConfig.MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS; import static android.net.vcn.VcnGatewayConnectionConfig.MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.net.NetworkCapabilities; @@ -29,6 +31,8 @@ import android.os.Parcel; import android.os.Parcelable; import android.telephony.SubscriptionManager; +import com.android.internal.util.Preconditions; + import java.util.Objects; /** @@ -47,6 +51,7 @@ import java.util.Objects; * * @hide */ +// TODO: Do not store WifiInfo and subscription ID in VcnTransportInfo anymore public class VcnTransportInfo implements TransportInfo, Parcelable { @Nullable private final WifiInfo mWifiInfo; private final int mSubId; @@ -195,4 +200,42 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { return new VcnTransportInfo[size]; } }; + + /** This class can be used to construct a {@link VcnTransportInfo}. */ + public static final class Builder { + private int mMinUdpPort4500NatTimeoutSeconds = MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET; + + /** Construct Builder */ + public Builder() {} + + /** + * Sets the maximum supported IKEv2/IPsec NATT keepalive timeout. + * + * <p>This is used as a power-optimization hint for other IKEv2/IPsec use cases (e.g. VPNs, + * or IWLAN) to reduce the necessary keepalive frequency, thus conserving power and data. + * + * @param minUdpPort4500NatTimeoutSeconds the maximum keepalive timeout supported by the VCN + * Gateway Connection, generally the minimum duration a NAT mapping is cached on the VCN + * Gateway. + * @return this {@link Builder} instance, for chaining + */ + @NonNull + public Builder setMinUdpPort4500NatTimeoutSeconds( + @IntRange(from = MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS) + int minUdpPort4500NatTimeoutSeconds) { + Preconditions.checkArgument( + minUdpPort4500NatTimeoutSeconds >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS, + "Timeout must be at least 120s"); + + mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds; + return Builder.this; + } + + /** Build a VcnTransportInfo instance */ + @NonNull + public VcnTransportInfo build() { + return new VcnTransportInfo( + null /* wifiInfo */, INVALID_SUBSCRIPTION_ID, mMinUdpPort4500NatTimeoutSeconds); + } + } } diff --git a/core/java/android/net/vcn/VcnUtils.java b/core/java/android/net/vcn/VcnUtils.java new file mode 100644 index 000000000000..6dc518097737 --- /dev/null +++ b/core/java/android/net/vcn/VcnUtils.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.net.vcn; + +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkSpecifier; +import android.net.TelephonyNetworkSpecifier; +import android.net.TransportInfo; +import android.net.wifi.WifiInfo; + +import java.util.List; + +/** + * Utility class for VCN callers get information from VCN network + * + * @hide + */ +public class VcnUtils { + /** Get the WifiInfo of the VCN's underlying WiFi network */ + @Nullable + public static WifiInfo getWifiInfoFromVcnCaps( + @NonNull ConnectivityManager connectivityMgr, + @NonNull NetworkCapabilities networkCapabilities) { + final NetworkCapabilities underlyingCaps = + getVcnUnderlyingCaps(connectivityMgr, networkCapabilities); + + if (underlyingCaps == null) { + return null; + } + + final TransportInfo underlyingTransportInfo = underlyingCaps.getTransportInfo(); + if (!(underlyingTransportInfo instanceof WifiInfo)) { + return null; + } + + return (WifiInfo) underlyingTransportInfo; + } + + /** Get the subscription ID of the VCN's underlying Cell network */ + public static int getSubIdFromVcnCaps( + @NonNull ConnectivityManager connectivityMgr, + @NonNull NetworkCapabilities networkCapabilities) { + final NetworkCapabilities underlyingCaps = + getVcnUnderlyingCaps(connectivityMgr, networkCapabilities); + + if (underlyingCaps == null) { + return INVALID_SUBSCRIPTION_ID; + } + + final NetworkSpecifier underlyingNetworkSpecifier = underlyingCaps.getNetworkSpecifier(); + if (!(underlyingNetworkSpecifier instanceof TelephonyNetworkSpecifier)) { + return INVALID_SUBSCRIPTION_ID; + } + + return ((TelephonyNetworkSpecifier) underlyingNetworkSpecifier).getSubscriptionId(); + } + + @Nullable + private static NetworkCapabilities getVcnUnderlyingCaps( + @NonNull ConnectivityManager connectivityMgr, + @NonNull NetworkCapabilities networkCapabilities) { + // Return null if it is not a VCN network + if (networkCapabilities.getTransportInfo() == null + || !(networkCapabilities.getTransportInfo() instanceof VcnTransportInfo)) { + return null; + } + + // As of Android 16, VCN has one underlying network, and only one. If there are more + // than one networks due to future changes in the VCN mainline code, just take the first + // network + final List<Network> underlyingNws = networkCapabilities.getUnderlyingNetworks(); + if (underlyingNws == null) { + return null; + } + + return connectivityMgr.getNetworkCapabilities(underlyingNws.get(0)); + } +} diff --git a/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java b/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java index 81814b67f5ee..7bc9970629a6 100644 --- a/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java +++ b/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java @@ -25,6 +25,7 @@ import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; import android.net.NetworkCapabilities; import android.net.wifi.WifiConfiguration; @@ -39,6 +40,7 @@ public class VcnTransportInfoTest { private static final int SUB_ID = 1; private static final int NETWORK_ID = 5; private static final int MIN_UDP_PORT_4500_NAT_TIMEOUT = 120; + private static final int MIN_UDP_PORT_4500_NAT_TIMEOUT_INVALID = 119; private static final WifiInfo WIFI_INFO = new WifiInfo.Builder().setNetworkId(NETWORK_ID).build(); @@ -48,6 +50,27 @@ public class VcnTransportInfoTest { new VcnTransportInfo(WIFI_INFO, MIN_UDP_PORT_4500_NAT_TIMEOUT); @Test + public void testBuilder() { + final VcnTransportInfo transportInfo = + new VcnTransportInfo.Builder() + .setMinUdpPort4500NatTimeoutSeconds(MIN_UDP_PORT_4500_NAT_TIMEOUT) + .build(); + + assertEquals( + MIN_UDP_PORT_4500_NAT_TIMEOUT, transportInfo.getMinUdpPort4500NatTimeoutSeconds()); + } + + @Test + public void testBuilder_withInvalidNatTimeout() { + try { + new VcnTransportInfo.Builder() + .setMinUdpPort4500NatTimeoutSeconds(MIN_UDP_PORT_4500_NAT_TIMEOUT_INVALID); + fail("Expected to fail due to invalid NAT timeout"); + } catch (Exception expected) { + } + } + + @Test public void testGetWifiInfo() { assertEquals(WIFI_INFO, WIFI_UNDERLYING_INFO.getWifiInfo()); diff --git a/tests/vcn/java/android/net/vcn/VcnUtilsTest.java b/tests/vcn/java/android/net/vcn/VcnUtilsTest.java new file mode 100644 index 000000000000..3ce6c8f9386d --- /dev/null +++ b/tests/vcn/java/android/net/vcn/VcnUtilsTest.java @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.vcn; + +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.TelephonyNetworkSpecifier; +import android.net.wifi.WifiInfo; + +import org.junit.Before; +import org.junit.Test; + +import java.util.Arrays; +import java.util.Collections; + +public class VcnUtilsTest { + private static final int SUB_ID = 1; + + private static final WifiInfo WIFI_INFO = new WifiInfo.Builder().build(); + private static final TelephonyNetworkSpecifier TEL_NETWORK_SPECIFIER = + new TelephonyNetworkSpecifier.Builder().setSubscriptionId(SUB_ID).build(); + private static final VcnTransportInfo VCN_TRANSPORT_INFO = + new VcnTransportInfo.Builder().build(); + + private ConnectivityManager mMockConnectivityManager; + private Network mMockWifiNetwork; + private Network mMockCellNetwork; + + private NetworkCapabilities mVcnCapsWithUnderlyingWifi; + private NetworkCapabilities mVcnCapsWithUnderlyingCell; + + @Before + public void setUp() { + mMockConnectivityManager = mock(ConnectivityManager.class); + + mMockWifiNetwork = mock(Network.class); + mVcnCapsWithUnderlyingWifi = newVcnCaps(VCN_TRANSPORT_INFO, mMockWifiNetwork); + final NetworkCapabilities wifiCaps = + new NetworkCapabilities.Builder() + .addTransportType(TRANSPORT_WIFI) + .setTransportInfo(WIFI_INFO) + .build(); + when(mMockConnectivityManager.getNetworkCapabilities(mMockWifiNetwork)) + .thenReturn(wifiCaps); + + mMockCellNetwork = mock(Network.class); + mVcnCapsWithUnderlyingCell = newVcnCaps(VCN_TRANSPORT_INFO, mMockCellNetwork); + final NetworkCapabilities cellCaps = + new NetworkCapabilities.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .setNetworkSpecifier(TEL_NETWORK_SPECIFIER) + .build(); + when(mMockConnectivityManager.getNetworkCapabilities(mMockCellNetwork)) + .thenReturn(cellCaps); + } + + private static NetworkCapabilities newVcnCaps( + VcnTransportInfo vcnTransportInfo, Network underlyingNetwork) { + return new NetworkCapabilities.Builder() + .setTransportInfo(vcnTransportInfo) + .setUnderlyingNetworks(Collections.singletonList(underlyingNetwork)) + .build(); + } + + @Test + public void getWifiInfoFromVcnCaps() { + assertEquals( + WIFI_INFO, + VcnUtils.getWifiInfoFromVcnCaps( + mMockConnectivityManager, mVcnCapsWithUnderlyingWifi)); + } + + @Test + public void getWifiInfoFromVcnCaps_onVcnWithUnderlyingCell() { + assertNull( + VcnUtils.getWifiInfoFromVcnCaps( + mMockConnectivityManager, mVcnCapsWithUnderlyingCell)); + } + + @Test + public void getSubIdFromVcnCaps() { + assertEquals( + SUB_ID, + VcnUtils.getSubIdFromVcnCaps(mMockConnectivityManager, mVcnCapsWithUnderlyingCell)); + } + + @Test + public void getSubIdFromVcnCaps_onVcnWithUnderlyingWifi() { + assertEquals( + INVALID_SUBSCRIPTION_ID, + VcnUtils.getSubIdFromVcnCaps(mMockConnectivityManager, mVcnCapsWithUnderlyingWifi)); + } + + @Test + public void getSubIdFromVcnCaps_onNonVcnNetwork() { + assertEquals( + INVALID_SUBSCRIPTION_ID, + VcnUtils.getSubIdFromVcnCaps( + mMockConnectivityManager, new NetworkCapabilities.Builder().build())); + } + + @Test + public void getSubIdFromVcnCaps_withMultipleUnderlyingNetworks() { + final NetworkCapabilities vcnCaps = + new NetworkCapabilities.Builder(mVcnCapsWithUnderlyingCell) + .setUnderlyingNetworks( + Arrays.asList( + new Network[] {mMockCellNetwork, mock(Network.class)})) + .build(); + assertEquals(SUB_ID, VcnUtils.getSubIdFromVcnCaps(mMockConnectivityManager, vcnCaps)); + } +} |