Support customization of supported keepalive count per transport
This change specifies the required minimum supported keepalives
in SDK, and allows OEMs to customize supported keepalive count
per network through resource overlay.
Bug: 129371366
Test: 1. m -j doc-comment-check-docs
2. atest FrameworksNetTests
Clean cherry-pick of aosp/946359
Change-Id: I06840834d0ee8121358bf4829fe47ecf9964d395
Merged-In: I0218f3674628c13ead63fc9a873895ba7f113033
Merged-In: Ia667386c1a8949839871a6949d79552d9c8b88f0
This commit is contained in:
@@ -43,6 +43,10 @@ import java.util.concurrent.Executor;
|
|||||||
* To stop an existing keepalive, call {@link SocketKeepalive#stop}. The system will call
|
* To stop an existing keepalive, call {@link SocketKeepalive#stop}. The system will call
|
||||||
* {@link SocketKeepalive.Callback#onStopped} if the operation was successful or
|
* {@link SocketKeepalive.Callback#onStopped} if the operation was successful or
|
||||||
* {@link SocketKeepalive.Callback#onError} if an error occurred.
|
* {@link SocketKeepalive.Callback#onError} if an error occurred.
|
||||||
|
*
|
||||||
|
* The device SHOULD support keepalive offload. If it does not, it MUST reply with
|
||||||
|
* {@link SocketKeepalive.Callback#onError} with {@code ERROR_UNSUPPORTED} to any keepalive offload
|
||||||
|
* request. If it does, it MUST support at least 3 concurrent keepalive slots per transport.
|
||||||
*/
|
*/
|
||||||
public abstract class SocketKeepalive implements AutoCloseable {
|
public abstract class SocketKeepalive implements AutoCloseable {
|
||||||
static final String TAG = "SocketKeepalive";
|
static final String TAG = "SocketKeepalive";
|
||||||
|
|||||||
121
core/java/android/net/util/KeepaliveUtils.java
Normal file
121
core/java/android/net/util/KeepaliveUtils.java
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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.util;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.net.NetworkCapabilities;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.util.AndroidRuntimeException;
|
||||||
|
|
||||||
|
import com.android.internal.R;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collection of utilities for socket keepalive offload.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public final class KeepaliveUtils {
|
||||||
|
|
||||||
|
public static final String TAG = "KeepaliveUtils";
|
||||||
|
|
||||||
|
// Minimum supported keepalive count per transport if the network supports keepalive.
|
||||||
|
public static final int MIN_SUPPORTED_KEEPALIVE_COUNT = 3;
|
||||||
|
|
||||||
|
public static class KeepaliveDeviceConfigurationException extends AndroidRuntimeException {
|
||||||
|
public KeepaliveDeviceConfigurationException(final String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read supported keepalive count for each transport type from overlay resource. This should be
|
||||||
|
* used to create a local variable store of resource customization, and use it as the input for
|
||||||
|
* {@link getSupportedKeepalivesForNetworkCapabilities}.
|
||||||
|
*
|
||||||
|
* @param context The context to read resource from.
|
||||||
|
* @return An array of supported keepalive count for each transport type.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public static int[] getSupportedKeepalives(@NonNull Context context) {
|
||||||
|
String[] res = null;
|
||||||
|
try {
|
||||||
|
res = context.getResources().getStringArray(
|
||||||
|
R.array.config_networkSupportedKeepaliveCount);
|
||||||
|
} catch (Resources.NotFoundException unused) {
|
||||||
|
}
|
||||||
|
if (res == null) throw new KeepaliveDeviceConfigurationException("invalid resource");
|
||||||
|
|
||||||
|
final int[] ret = new int[NetworkCapabilities.MAX_TRANSPORT + 1];
|
||||||
|
for (final String row : res) {
|
||||||
|
if (TextUtils.isEmpty(row)) {
|
||||||
|
throw new KeepaliveDeviceConfigurationException("Empty string");
|
||||||
|
}
|
||||||
|
final String[] arr = row.split(",");
|
||||||
|
if (arr.length != 2) {
|
||||||
|
throw new KeepaliveDeviceConfigurationException("Invalid parameter length");
|
||||||
|
}
|
||||||
|
|
||||||
|
int transport;
|
||||||
|
int supported;
|
||||||
|
try {
|
||||||
|
transport = Integer.parseInt(arr[0]);
|
||||||
|
supported = Integer.parseInt(arr[1]);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new KeepaliveDeviceConfigurationException("Invalid number format");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!NetworkCapabilities.isValidTransport(transport)) {
|
||||||
|
throw new KeepaliveDeviceConfigurationException("Invalid transport " + transport);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Customized values should be either 0 to indicate the network doesn't support
|
||||||
|
// keepalive offload, or a positive value that is at least
|
||||||
|
// MIN_SUPPORTED_KEEPALIVE_COUNT if supported.
|
||||||
|
if (supported != 0 && supported < MIN_SUPPORTED_KEEPALIVE_COUNT) {
|
||||||
|
throw new KeepaliveDeviceConfigurationException(
|
||||||
|
"Invalid supported count " + supported + " for "
|
||||||
|
+ NetworkCapabilities.transportNameOf(transport));
|
||||||
|
}
|
||||||
|
ret[transport] = supported;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get supported keepalive count for the given {@link NetworkCapabilities}.
|
||||||
|
*
|
||||||
|
* @param supportedKeepalives An array of supported keepalive count for each transport type.
|
||||||
|
* @param nc The {@link NetworkCapabilities} of the network the socket keepalive is on.
|
||||||
|
*
|
||||||
|
* @return Supported keepalive count for the given {@link NetworkCapabilities}.
|
||||||
|
*/
|
||||||
|
public static int getSupportedKeepalivesForNetworkCapabilities(
|
||||||
|
@NonNull int[] supportedKeepalives, @NonNull NetworkCapabilities nc) {
|
||||||
|
final int[] transports = nc.getTransportTypes();
|
||||||
|
if (transports.length == 0) return 0;
|
||||||
|
int supportedCount = supportedKeepalives[transports[0]];
|
||||||
|
// Iterate through transports and return minimum supported value.
|
||||||
|
for (final int transport : transports) {
|
||||||
|
if (supportedCount > supportedKeepalives[transport]) {
|
||||||
|
supportedCount = supportedKeepalives[transport];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return supportedCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,6 +29,7 @@ import static android.net.SocketKeepalive.ERROR_INVALID_INTERVAL;
|
|||||||
import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS;
|
import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS;
|
||||||
import static android.net.SocketKeepalive.ERROR_INVALID_NETWORK;
|
import static android.net.SocketKeepalive.ERROR_INVALID_NETWORK;
|
||||||
import static android.net.SocketKeepalive.ERROR_INVALID_SOCKET;
|
import static android.net.SocketKeepalive.ERROR_INVALID_SOCKET;
|
||||||
|
import static android.net.SocketKeepalive.ERROR_UNSUPPORTED;
|
||||||
import static android.net.SocketKeepalive.MAX_INTERVAL_SEC;
|
import static android.net.SocketKeepalive.MAX_INTERVAL_SEC;
|
||||||
import static android.net.SocketKeepalive.MIN_INTERVAL_SEC;
|
import static android.net.SocketKeepalive.MIN_INTERVAL_SEC;
|
||||||
import static android.net.SocketKeepalive.NO_KEEPALIVE;
|
import static android.net.SocketKeepalive.NO_KEEPALIVE;
|
||||||
@@ -46,6 +47,7 @@ import android.net.SocketKeepalive.InvalidPacketException;
|
|||||||
import android.net.SocketKeepalive.InvalidSocketException;
|
import android.net.SocketKeepalive.InvalidSocketException;
|
||||||
import android.net.TcpKeepalivePacketData;
|
import android.net.TcpKeepalivePacketData;
|
||||||
import android.net.util.IpUtils;
|
import android.net.util.IpUtils;
|
||||||
|
import android.net.util.KeepaliveUtils;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
@@ -57,6 +59,7 @@ import android.system.Os;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
||||||
|
import com.android.internal.R;
|
||||||
import com.android.internal.util.HexDump;
|
import com.android.internal.util.HexDump;
|
||||||
import com.android.internal.util.IndentingPrintWriter;
|
import com.android.internal.util.IndentingPrintWriter;
|
||||||
|
|
||||||
@@ -65,6 +68,7 @@ import java.net.InetAddress;
|
|||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -90,10 +94,23 @@ public class KeepaliveTracker {
|
|||||||
@NonNull
|
@NonNull
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
|
|
||||||
|
// Supported keepalive count for each transport type, can be configured through
|
||||||
|
// config_networkSupportedKeepaliveCount. For better error handling, use
|
||||||
|
// {@link getSupportedKeepalivesForNetworkCapabilities} instead of direct access.
|
||||||
|
@NonNull
|
||||||
|
private final int[] mSupportedKeepalives;
|
||||||
|
|
||||||
|
// Reserved privileged keepalive slots per transport. Caller's permission will be enforced if
|
||||||
|
// the number of remaining keepalive slots is less than or equal to the threshold.
|
||||||
|
private final int mReservedPrivilegedSlots;
|
||||||
|
|
||||||
public KeepaliveTracker(Context context, Handler handler) {
|
public KeepaliveTracker(Context context, Handler handler) {
|
||||||
mConnectivityServiceHandler = handler;
|
mConnectivityServiceHandler = handler;
|
||||||
mTcpController = new TcpKeepaliveController(handler);
|
mTcpController = new TcpKeepaliveController(handler);
|
||||||
mContext = context;
|
mContext = context;
|
||||||
|
mSupportedKeepalives = KeepaliveUtils.getSupportedKeepalives(mContext);
|
||||||
|
mReservedPrivilegedSlots = mContext.getResources().getInteger(
|
||||||
|
R.integer.config_reservedPrivilegedKeepaliveSlots);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -115,11 +132,6 @@ public class KeepaliveTracker {
|
|||||||
public static final int TYPE_NATT = 1;
|
public static final int TYPE_NATT = 1;
|
||||||
public static final int TYPE_TCP = 2;
|
public static final int TYPE_TCP = 2;
|
||||||
|
|
||||||
// Max allowed unprivileged keepalive slots per network. Caller's permission will be
|
|
||||||
// enforced if number of existing keepalives reach this limit.
|
|
||||||
// TODO: consider making this limit configurable via resources.
|
|
||||||
private static final int MAX_UNPRIVILEGED_SLOTS = 3;
|
|
||||||
|
|
||||||
// Keepalive slot. A small integer that identifies this keepalive among the ones handled
|
// Keepalive slot. A small integer that identifies this keepalive among the ones handled
|
||||||
// by this network.
|
// by this network.
|
||||||
private int mSlot = NO_KEEPALIVE;
|
private int mSlot = NO_KEEPALIVE;
|
||||||
@@ -246,24 +258,42 @@ public class KeepaliveTracker {
|
|||||||
|
|
||||||
private int checkPermission() {
|
private int checkPermission() {
|
||||||
final HashMap<Integer, KeepaliveInfo> networkKeepalives = mKeepalives.get(mNai);
|
final HashMap<Integer, KeepaliveInfo> networkKeepalives = mKeepalives.get(mNai);
|
||||||
int unprivilegedCount = 0;
|
|
||||||
if (networkKeepalives == null) {
|
if (networkKeepalives == null) {
|
||||||
return ERROR_INVALID_NETWORK;
|
return ERROR_INVALID_NETWORK;
|
||||||
}
|
}
|
||||||
for (KeepaliveInfo ki : networkKeepalives.values()) {
|
|
||||||
if (!ki.mPrivileged) {
|
if (mPrivileged) return SUCCESS;
|
||||||
unprivilegedCount++;
|
|
||||||
}
|
final int supported = KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(
|
||||||
if (unprivilegedCount >= MAX_UNPRIVILEGED_SLOTS) {
|
mSupportedKeepalives, mNai.networkCapabilities);
|
||||||
return mPrivileged ? SUCCESS : ERROR_INSUFFICIENT_RESOURCES;
|
|
||||||
}
|
int takenUnprivilegedSlots = 0;
|
||||||
|
for (final KeepaliveInfo ki : networkKeepalives.values()) {
|
||||||
|
if (!ki.mPrivileged) ++takenUnprivilegedSlots;
|
||||||
}
|
}
|
||||||
|
if (takenUnprivilegedSlots > supported - mReservedPrivilegedSlots) {
|
||||||
|
return ERROR_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int checkLimit() {
|
||||||
|
final HashMap<Integer, KeepaliveInfo> networkKeepalives = mKeepalives.get(mNai);
|
||||||
|
if (networkKeepalives == null) {
|
||||||
|
return ERROR_INVALID_NETWORK;
|
||||||
|
}
|
||||||
|
final int supported = KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(
|
||||||
|
mSupportedKeepalives, mNai.networkCapabilities);
|
||||||
|
if (supported == 0) return ERROR_UNSUPPORTED;
|
||||||
|
if (networkKeepalives.size() > supported) return ERROR_INSUFFICIENT_RESOURCES;
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int isValid() {
|
private int isValid() {
|
||||||
synchronized (mNai) {
|
synchronized (mNai) {
|
||||||
int error = checkInterval();
|
int error = checkInterval();
|
||||||
|
if (error == SUCCESS) error = checkLimit();
|
||||||
if (error == SUCCESS) error = checkPermission();
|
if (error == SUCCESS) error = checkPermission();
|
||||||
if (error == SUCCESS) error = checkNetworkConnected();
|
if (error == SUCCESS) error = checkNetworkConnected();
|
||||||
if (error == SUCCESS) error = checkSourceAddress();
|
if (error == SUCCESS) error = checkSourceAddress();
|
||||||
@@ -642,6 +672,8 @@ public class KeepaliveTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void dump(IndentingPrintWriter pw) {
|
public void dump(IndentingPrintWriter pw) {
|
||||||
|
pw.println("Supported Socket keepalives: " + Arrays.toString(mSupportedKeepalives));
|
||||||
|
pw.println("Reserved Privileged keepalives: " + mReservedPrivilegedSlots);
|
||||||
pw.println("Socket keepalives:");
|
pw.println("Socket keepalives:");
|
||||||
pw.increaseIndent();
|
pw.increaseIndent();
|
||||||
for (NetworkAgentInfo nai : mKeepalives.keySet()) {
|
for (NetworkAgentInfo nai : mKeepalives.keySet()) {
|
||||||
|
|||||||
130
tests/net/java/android/net/util/KeepaliveUtilsTest.kt
Normal file
130
tests/net/java/android/net/util/KeepaliveUtilsTest.kt
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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.util
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.res.Resources
|
||||||
|
import android.net.NetworkCapabilities
|
||||||
|
import android.net.NetworkCapabilities.MAX_TRANSPORT
|
||||||
|
import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
|
||||||
|
import android.net.NetworkCapabilities.TRANSPORT_ETHERNET
|
||||||
|
import android.net.NetworkCapabilities.TRANSPORT_VPN
|
||||||
|
import android.net.NetworkCapabilities.TRANSPORT_WIFI
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.internal.R
|
||||||
|
import org.junit.Assert.assertArrayEquals
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.fail
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.junit.runners.JUnit4
|
||||||
|
import org.mockito.ArgumentMatchers
|
||||||
|
import org.mockito.Mockito.doReturn
|
||||||
|
import org.mockito.Mockito.mock
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for [KeepaliveUtils].
|
||||||
|
*
|
||||||
|
* Build, install and run with:
|
||||||
|
* atest android.net.util.KeepaliveUtilsTest
|
||||||
|
*/
|
||||||
|
@RunWith(JUnit4::class)
|
||||||
|
@SmallTest
|
||||||
|
class KeepaliveUtilsTest {
|
||||||
|
|
||||||
|
// Prepare mocked context with given resource strings.
|
||||||
|
private fun getMockedContextWithStringArrayRes(id: Int, res: Array<out String?>?): Context {
|
||||||
|
val mockRes = mock(Resources::class.java)
|
||||||
|
doReturn(res).`when`(mockRes).getStringArray(ArgumentMatchers.eq(id))
|
||||||
|
|
||||||
|
return mock(Context::class.java).apply {
|
||||||
|
doReturn(mockRes).`when`(this).getResources()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testGetSupportedKeepalives() {
|
||||||
|
fun assertRunWithException(res: Array<out String?>?) {
|
||||||
|
try {
|
||||||
|
val mockContext = getMockedContextWithStringArrayRes(
|
||||||
|
R.array.config_networkSupportedKeepaliveCount, res)
|
||||||
|
KeepaliveUtils.getSupportedKeepalives(mockContext)
|
||||||
|
fail("Expected KeepaliveDeviceConfigurationException")
|
||||||
|
} catch (expected: KeepaliveUtils.KeepaliveDeviceConfigurationException) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check resource with various invalid format.
|
||||||
|
assertRunWithException(null)
|
||||||
|
assertRunWithException(arrayOf<String?>(null))
|
||||||
|
assertRunWithException(arrayOfNulls<String?>(10))
|
||||||
|
assertRunWithException(arrayOf(""))
|
||||||
|
assertRunWithException(arrayOf("3,ABC"))
|
||||||
|
assertRunWithException(arrayOf("6,3,3"))
|
||||||
|
assertRunWithException(arrayOf("5"))
|
||||||
|
|
||||||
|
// Check resource with invalid slots value.
|
||||||
|
assertRunWithException(arrayOf("2,2"))
|
||||||
|
assertRunWithException(arrayOf("3,-1"))
|
||||||
|
|
||||||
|
// Check resource with invalid transport type.
|
||||||
|
assertRunWithException(arrayOf("-1,3"))
|
||||||
|
assertRunWithException(arrayOf("10,3"))
|
||||||
|
|
||||||
|
// Check valid customization generates expected array.
|
||||||
|
val validRes = arrayOf("0,3", "1,0", "4,4")
|
||||||
|
val expectedValidRes = intArrayOf(3, 0, 0, 0, 4, 0, 0, 0)
|
||||||
|
|
||||||
|
val mockContext = getMockedContextWithStringArrayRes(
|
||||||
|
R.array.config_networkSupportedKeepaliveCount, validRes)
|
||||||
|
val actual = KeepaliveUtils.getSupportedKeepalives(mockContext)
|
||||||
|
assertArrayEquals(expectedValidRes, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testGetSupportedKeepalivesForNetworkCapabilities() {
|
||||||
|
// Mock customized supported keepalives for each transport type, and assuming:
|
||||||
|
// 3 for cellular,
|
||||||
|
// 6 for wifi,
|
||||||
|
// 0 for others.
|
||||||
|
val cust = IntArray(MAX_TRANSPORT + 1).apply {
|
||||||
|
this[TRANSPORT_CELLULAR] = 3
|
||||||
|
this[TRANSPORT_WIFI] = 6
|
||||||
|
}
|
||||||
|
|
||||||
|
val nc = NetworkCapabilities()
|
||||||
|
// Check supported keepalives with single transport type.
|
||||||
|
nc.transportTypes = intArrayOf(TRANSPORT_CELLULAR)
|
||||||
|
assertEquals(3, KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(cust, nc))
|
||||||
|
|
||||||
|
// Check supported keepalives with multiple transport types.
|
||||||
|
nc.transportTypes = intArrayOf(TRANSPORT_WIFI, TRANSPORT_VPN)
|
||||||
|
assertEquals(0, KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(cust, nc))
|
||||||
|
|
||||||
|
// Check supported keepalives with non-customized transport type.
|
||||||
|
nc.transportTypes = intArrayOf(TRANSPORT_ETHERNET)
|
||||||
|
assertEquals(0, KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(cust, nc))
|
||||||
|
|
||||||
|
// Check supported keepalives with undefined transport type.
|
||||||
|
nc.transportTypes = intArrayOf(MAX_TRANSPORT + 1)
|
||||||
|
try {
|
||||||
|
KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(cust, nc)
|
||||||
|
fail("Expected ArrayIndexOutOfBoundsException")
|
||||||
|
} catch (expected: ArrayIndexOutOfBoundsException) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user