Files
frameworks_base/tests/net/java/com/android/server/IpSecServiceTest.java
Luke Huang e8e522bb31 Use ParcelFileDescriptor instead of FileDescriptor in INetd.aidl
Stable aidl won't support FileDescriptor but ParcelFileDescriptor.
In order to migrate to stable aidl, replace all FileDescriptor in
INdetd.aidl.

Test: runtest frameworks-net passes
Change-Id: Icdf37aed0e0cce0352070a437066e77c0f2fd85a
2018-11-28 13:41:58 +08:00

660 lines
25 KiB
Java

/*
* Copyright (C) 2017 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 com.android.server;
import static android.system.OsConstants.AF_INET;
import static android.system.OsConstants.EADDRINUSE;
import static android.system.OsConstants.IPPROTO_UDP;
import static android.system.OsConstants.SOCK_DGRAM;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.argThat;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.net.INetd;
import android.net.IpSecAlgorithm;
import android.net.IpSecConfig;
import android.net.IpSecManager;
import android.net.IpSecSpiResponse;
import android.net.IpSecTransform;
import android.net.IpSecUdpEncapResponse;
import android.os.Binder;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.system.ErrnoException;
import android.system.Os;
import android.system.StructStat;
import dalvik.system.SocketTagger;
import java.io.FileDescriptor;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatcher;
/** Unit tests for {@link IpSecService}. */
@SmallTest
@RunWith(AndroidJUnit4.class)
public class IpSecServiceTest {
private static final int DROID_SPI = 0xD1201D;
private static final int MAX_NUM_ENCAP_SOCKETS = 100;
private static final int MAX_NUM_SPIS = 100;
private static final int TEST_UDP_ENCAP_INVALID_PORT = 100;
private static final int TEST_UDP_ENCAP_PORT_OUT_RANGE = 100000;
private static final InetAddress INADDR_ANY;
private static final byte[] AEAD_KEY = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x73, 0x61, 0x6C, 0x74
};
private static final byte[] CRYPT_KEY = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
};
private static final byte[] AUTH_KEY = {
0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F,
0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F
};
private static final IpSecAlgorithm AUTH_ALGO =
new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4);
private static final IpSecAlgorithm CRYPT_ALGO =
new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
private static final IpSecAlgorithm AEAD_ALGO =
new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
static {
try {
INADDR_ANY = InetAddress.getByAddress(new byte[] {0, 0, 0, 0});
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
}
Context mMockContext;
INetd mMockNetd;
IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
IpSecService mIpSecService;
@Before
public void setUp() throws Exception {
mMockContext = mock(Context.class);
mMockNetd = mock(INetd.class);
mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig);
// Injecting mock netd
when(mMockIpSecSrvConfig.getNetdInstance()).thenReturn(mMockNetd);
}
@Test
public void testIpSecServiceCreate() throws InterruptedException {
IpSecService ipSecSrv = IpSecService.create(mMockContext);
assertNotNull(ipSecSrv);
}
@Test
public void testReleaseInvalidSecurityParameterIndex() throws Exception {
try {
mIpSecService.releaseSecurityParameterIndex(1);
fail("IllegalArgumentException not thrown");
} catch (IllegalArgumentException e) {
}
}
/** This function finds an available port */
int findUnusedPort() throws Exception {
// Get an available port.
ServerSocket s = new ServerSocket(0);
int port = s.getLocalPort();
s.close();
return port;
}
@Test
public void testOpenAndCloseUdpEncapsulationSocket() throws Exception {
int localport = findUnusedPort();
IpSecUdpEncapResponse udpEncapResp =
mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
assertNotNull(udpEncapResp);
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
assertEquals(localport, udpEncapResp.port);
mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
udpEncapResp.fileDescriptor.close();
// Verify quota and RefcountedResource objects cleaned up
IpSecService.UserRecord userRecord =
mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
assertEquals(0, userRecord.mSocketQuotaTracker.mCurrent);
try {
userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow(udpEncapResp.resourceId);
fail("Expected IllegalArgumentException on attempt to access deleted resource");
} catch (IllegalArgumentException expected) {
}
}
@Test
public void testUdpEncapsulationSocketBinderDeath() throws Exception {
IpSecUdpEncapResponse udpEncapResp =
mIpSecService.openUdpEncapsulationSocket(0, new Binder());
IpSecService.UserRecord userRecord =
mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
IpSecService.RefcountedResource refcountedRecord =
userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow(
udpEncapResp.resourceId);
refcountedRecord.binderDied();
// Verify quota and RefcountedResource objects cleaned up
assertEquals(0, userRecord.mSocketQuotaTracker.mCurrent);
try {
userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow(udpEncapResp.resourceId);
fail("Expected IllegalArgumentException on attempt to access deleted resource");
} catch (IllegalArgumentException expected) {
}
}
@Test
public void testOpenUdpEncapsulationSocketAfterClose() throws Exception {
int localport = findUnusedPort();
IpSecUdpEncapResponse udpEncapResp =
mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
assertNotNull(udpEncapResp);
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
assertEquals(localport, udpEncapResp.port);
mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
udpEncapResp.fileDescriptor.close();
/** Check if localport is available. */
FileDescriptor newSocket = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
Os.bind(newSocket, INADDR_ANY, localport);
Os.close(newSocket);
}
/**
* This function checks if the IpSecService holds the reserved port. If
* closeUdpEncapsulationSocket is not called, the socket cleanup should not be complete.
*/
@Test
public void testUdpEncapPortNotReleased() throws Exception {
int localport = findUnusedPort();
IpSecUdpEncapResponse udpEncapResp =
mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
assertNotNull(udpEncapResp);
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
assertEquals(localport, udpEncapResp.port);
udpEncapResp.fileDescriptor.close();
FileDescriptor newSocket = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
try {
Os.bind(newSocket, INADDR_ANY, localport);
fail("ErrnoException not thrown");
} catch (ErrnoException e) {
assertEquals(EADDRINUSE, e.errno);
}
mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
}
@Test
public void testOpenUdpEncapsulationSocketOnRandomPort() throws Exception {
IpSecUdpEncapResponse udpEncapResp =
mIpSecService.openUdpEncapsulationSocket(0, new Binder());
assertNotNull(udpEncapResp);
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
assertNotEquals(0, udpEncapResp.port);
mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
udpEncapResp.fileDescriptor.close();
}
@Test
public void testOpenUdpEncapsulationSocketPortRange() throws Exception {
try {
mIpSecService.openUdpEncapsulationSocket(TEST_UDP_ENCAP_INVALID_PORT, new Binder());
fail("IllegalArgumentException not thrown");
} catch (IllegalArgumentException e) {
}
try {
mIpSecService.openUdpEncapsulationSocket(TEST_UDP_ENCAP_PORT_OUT_RANGE, new Binder());
fail("IllegalArgumentException not thrown");
} catch (IllegalArgumentException e) {
}
}
@Test
public void testOpenUdpEncapsulationSocketTwice() throws Exception {
int localport = findUnusedPort();
IpSecUdpEncapResponse udpEncapResp =
mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
assertNotNull(udpEncapResp);
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
assertEquals(localport, udpEncapResp.port);
mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
IpSecUdpEncapResponse testUdpEncapResp =
mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
assertEquals(IpSecManager.Status.RESOURCE_UNAVAILABLE, testUdpEncapResp.status);
mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
udpEncapResp.fileDescriptor.close();
}
@Test
public void testCloseInvalidUdpEncapsulationSocket() throws Exception {
try {
mIpSecService.closeUdpEncapsulationSocket(1);
fail("IllegalArgumentException not thrown");
} catch (IllegalArgumentException e) {
}
}
@Test
public void testValidateAlgorithmsAuth() {
// Validate that correct algorithm type succeeds
IpSecConfig config = new IpSecConfig();
config.setAuthentication(AUTH_ALGO);
mIpSecService.validateAlgorithms(config);
// Validate that incorrect algorithm types fails
for (IpSecAlgorithm algo : new IpSecAlgorithm[] {CRYPT_ALGO, AEAD_ALGO}) {
try {
config = new IpSecConfig();
config.setAuthentication(algo);
mIpSecService.validateAlgorithms(config);
fail("Did not throw exception on invalid algorithm type");
} catch (IllegalArgumentException expected) {
}
}
}
@Test
public void testValidateAlgorithmsCrypt() {
// Validate that correct algorithm type succeeds
IpSecConfig config = new IpSecConfig();
config.setEncryption(CRYPT_ALGO);
mIpSecService.validateAlgorithms(config);
// Validate that incorrect algorithm types fails
for (IpSecAlgorithm algo : new IpSecAlgorithm[] {AUTH_ALGO, AEAD_ALGO}) {
try {
config = new IpSecConfig();
config.setEncryption(algo);
mIpSecService.validateAlgorithms(config);
fail("Did not throw exception on invalid algorithm type");
} catch (IllegalArgumentException expected) {
}
}
}
@Test
public void testValidateAlgorithmsAead() {
// Validate that correct algorithm type succeeds
IpSecConfig config = new IpSecConfig();
config.setAuthenticatedEncryption(AEAD_ALGO);
mIpSecService.validateAlgorithms(config);
// Validate that incorrect algorithm types fails
for (IpSecAlgorithm algo : new IpSecAlgorithm[] {AUTH_ALGO, CRYPT_ALGO}) {
try {
config = new IpSecConfig();
config.setAuthenticatedEncryption(algo);
mIpSecService.validateAlgorithms(config);
fail("Did not throw exception on invalid algorithm type");
} catch (IllegalArgumentException expected) {
}
}
}
@Test
public void testValidateAlgorithmsAuthCrypt() {
// Validate that correct algorithm type succeeds
IpSecConfig config = new IpSecConfig();
config.setAuthentication(AUTH_ALGO);
config.setEncryption(CRYPT_ALGO);
mIpSecService.validateAlgorithms(config);
}
@Test
public void testValidateAlgorithmsNoAlgorithms() {
IpSecConfig config = new IpSecConfig();
try {
mIpSecService.validateAlgorithms(config);
fail("Expected exception; no algorithms specified");
} catch (IllegalArgumentException expected) {
}
}
@Test
public void testValidateAlgorithmsAeadWithAuth() {
IpSecConfig config = new IpSecConfig();
config.setAuthenticatedEncryption(AEAD_ALGO);
config.setAuthentication(AUTH_ALGO);
try {
mIpSecService.validateAlgorithms(config);
fail("Expected exception; both AEAD and auth algorithm specified");
} catch (IllegalArgumentException expected) {
}
}
@Test
public void testValidateAlgorithmsAeadWithCrypt() {
IpSecConfig config = new IpSecConfig();
config.setAuthenticatedEncryption(AEAD_ALGO);
config.setEncryption(CRYPT_ALGO);
try {
mIpSecService.validateAlgorithms(config);
fail("Expected exception; both AEAD and crypt algorithm specified");
} catch (IllegalArgumentException expected) {
}
}
@Test
public void testValidateAlgorithmsAeadWithAuthAndCrypt() {
IpSecConfig config = new IpSecConfig();
config.setAuthenticatedEncryption(AEAD_ALGO);
config.setAuthentication(AUTH_ALGO);
config.setEncryption(CRYPT_ALGO);
try {
mIpSecService.validateAlgorithms(config);
fail("Expected exception; AEAD, auth and crypt algorithm specified");
} catch (IllegalArgumentException expected) {
}
}
@Test
public void testDeleteInvalidTransform() throws Exception {
try {
mIpSecService.deleteTransform(1);
fail("IllegalArgumentException not thrown");
} catch (IllegalArgumentException e) {
}
}
@Test
public void testRemoveTransportModeTransform() throws Exception {
ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
mIpSecService.removeTransportModeTransforms(pfd);
verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd);
}
@Test
public void testValidateIpAddresses() throws Exception {
String[] invalidAddresses =
new String[] {"www.google.com", "::", "2001::/64", "0.0.0.0", ""};
for (String address : invalidAddresses) {
try {
IpSecSpiResponse spiResp =
mIpSecService.allocateSecurityParameterIndex(
address, DROID_SPI, new Binder());
fail("Invalid address was passed through IpSecService validation: " + address);
} catch (IllegalArgumentException e) {
} catch (Exception e) {
fail(
"Invalid InetAddress was not caught in validation: "
+ address
+ ", Exception: "
+ e);
}
}
}
/**
* This function checks if the number of encap UDP socket that one UID can reserve has a
* reasonable limit.
*/
@Test
public void testSocketResourceTrackerLimitation() throws Exception {
List<IpSecUdpEncapResponse> openUdpEncapSockets = new ArrayList<IpSecUdpEncapResponse>();
// Reserve sockets until it fails.
for (int i = 0; i < MAX_NUM_ENCAP_SOCKETS; i++) {
IpSecUdpEncapResponse newUdpEncapSocket =
mIpSecService.openUdpEncapsulationSocket(0, new Binder());
assertNotNull(newUdpEncapSocket);
if (IpSecManager.Status.OK != newUdpEncapSocket.status) {
break;
}
openUdpEncapSockets.add(newUdpEncapSocket);
}
// Assert that the total sockets quota has a reasonable limit.
assertTrue("No UDP encap socket was open", !openUdpEncapSockets.isEmpty());
assertTrue(
"Number of open UDP encap sockets is out of bound",
openUdpEncapSockets.size() < MAX_NUM_ENCAP_SOCKETS);
// Try to reserve one more UDP encapsulation socket, and should fail.
IpSecUdpEncapResponse extraUdpEncapSocket =
mIpSecService.openUdpEncapsulationSocket(0, new Binder());
assertNotNull(extraUdpEncapSocket);
assertEquals(IpSecManager.Status.RESOURCE_UNAVAILABLE, extraUdpEncapSocket.status);
// Close one of the open UDP encapsulation sockets.
mIpSecService.closeUdpEncapsulationSocket(openUdpEncapSockets.get(0).resourceId);
openUdpEncapSockets.get(0).fileDescriptor.close();
openUdpEncapSockets.remove(0);
// Try to reserve one more UDP encapsulation socket, and should be successful.
extraUdpEncapSocket = mIpSecService.openUdpEncapsulationSocket(0, new Binder());
assertNotNull(extraUdpEncapSocket);
assertEquals(IpSecManager.Status.OK, extraUdpEncapSocket.status);
openUdpEncapSockets.add(extraUdpEncapSocket);
// Close open UDP sockets.
for (IpSecUdpEncapResponse openSocket : openUdpEncapSockets) {
mIpSecService.closeUdpEncapsulationSocket(openSocket.resourceId);
openSocket.fileDescriptor.close();
}
}
/**
* This function checks if the number of SPI that one UID can reserve has a reasonable limit.
* This test does not test for both address families or duplicate SPIs because resource tracking
* code does not depend on them.
*/
@Test
public void testSpiResourceTrackerLimitation() throws Exception {
List<IpSecSpiResponse> reservedSpis = new ArrayList<IpSecSpiResponse>();
// Return the same SPI for all SPI allocation since IpSecService only
// tracks the resource ID.
when(mMockNetd.ipSecAllocateSpi(
anyInt(),
anyString(),
eq(InetAddress.getLoopbackAddress().getHostAddress()),
anyInt()))
.thenReturn(DROID_SPI);
// Reserve spis until it fails.
for (int i = 0; i < MAX_NUM_SPIS; i++) {
IpSecSpiResponse newSpi =
mIpSecService.allocateSecurityParameterIndex(
InetAddress.getLoopbackAddress().getHostAddress(),
DROID_SPI + i,
new Binder());
assertNotNull(newSpi);
if (IpSecManager.Status.OK != newSpi.status) {
break;
}
reservedSpis.add(newSpi);
}
// Assert that the SPI quota has a reasonable limit.
assertTrue(reservedSpis.size() > 0 && reservedSpis.size() < MAX_NUM_SPIS);
// Try to reserve one more SPI, and should fail.
IpSecSpiResponse extraSpi =
mIpSecService.allocateSecurityParameterIndex(
InetAddress.getLoopbackAddress().getHostAddress(),
DROID_SPI + MAX_NUM_SPIS,
new Binder());
assertNotNull(extraSpi);
assertEquals(IpSecManager.Status.RESOURCE_UNAVAILABLE, extraSpi.status);
// Release one reserved spi.
mIpSecService.releaseSecurityParameterIndex(reservedSpis.get(0).resourceId);
reservedSpis.remove(0);
// Should successfully reserve one more spi.
extraSpi =
mIpSecService.allocateSecurityParameterIndex(
InetAddress.getLoopbackAddress().getHostAddress(),
DROID_SPI + MAX_NUM_SPIS,
new Binder());
assertNotNull(extraSpi);
assertEquals(IpSecManager.Status.OK, extraSpi.status);
// Release reserved SPIs.
for (IpSecSpiResponse spiResp : reservedSpis) {
mIpSecService.releaseSecurityParameterIndex(spiResp.resourceId);
}
}
@Test
public void testUidFdtagger() throws Exception {
SocketTagger actualSocketTagger = SocketTagger.get();
try {
FileDescriptor sockFd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
// Has to be done after socket creation because BlockGuardOS calls tag on new sockets
SocketTagger mockSocketTagger = mock(SocketTagger.class);
SocketTagger.set(mockSocketTagger);
mIpSecService.mUidFdTagger.tag(sockFd, Process.LAST_APPLICATION_UID);
verify(mockSocketTagger).tag(eq(sockFd));
} finally {
SocketTagger.set(actualSocketTagger);
}
}
/**
* Checks if two file descriptors point to the same file.
*
* <p>According to stat.h documentation, the correct way to check for equivalent or duplicated
* file descriptors is to check their inode and device. These two entries uniquely identify any
* file.
*/
private boolean fileDescriptorsEqual(FileDescriptor fd1, FileDescriptor fd2) {
try {
StructStat fd1Stat = Os.fstat(fd1);
StructStat fd2Stat = Os.fstat(fd2);
return fd1Stat.st_ino == fd2Stat.st_ino && fd1Stat.st_dev == fd2Stat.st_dev;
} catch (ErrnoException e) {
return false;
}
}
@Test
public void testOpenUdpEncapSocketTagsSocket() throws Exception {
IpSecService.UidFdTagger mockTagger = mock(IpSecService.UidFdTagger.class);
IpSecService testIpSecService =
new IpSecService(mMockContext, mMockIpSecSrvConfig, mockTagger);
IpSecUdpEncapResponse udpEncapResp =
testIpSecService.openUdpEncapsulationSocket(0, new Binder());
assertNotNull(udpEncapResp);
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
FileDescriptor sockFd = udpEncapResp.fileDescriptor.getFileDescriptor();
ArgumentMatcher<FileDescriptor> fdMatcher =
(argFd) -> {
return fileDescriptorsEqual(sockFd, argFd);
};
verify(mockTagger).tag(argThat(fdMatcher), eq(Os.getuid()));
testIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
udpEncapResp.fileDescriptor.close();
}
@Test
public void testOpenUdpEncapsulationSocketCallsSetEncapSocketOwner() throws Exception {
IpSecUdpEncapResponse udpEncapResp =
mIpSecService.openUdpEncapsulationSocket(0, new Binder());
FileDescriptor sockFd = udpEncapResp.fileDescriptor.getFileDescriptor();
ArgumentMatcher<ParcelFileDescriptor> fdMatcher = (arg) -> {
try {
StructStat sockStat = Os.fstat(sockFd);
StructStat argStat = Os.fstat(arg.getFileDescriptor());
return sockStat.st_ino == argStat.st_ino
&& sockStat.st_dev == argStat.st_dev;
} catch (ErrnoException e) {
return false;
}
};
verify(mMockNetd).ipSecSetEncapSocketOwner(argThat(fdMatcher), eq(Os.getuid()));
mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
}
@Test
public void testReserveNetId() {
int start = mIpSecService.TUN_INTF_NETID_START;
for (int i = 0; i < mIpSecService.TUN_INTF_NETID_RANGE; i++) {
assertEquals(start + i, mIpSecService.reserveNetId());
}
// Check that resource exhaustion triggers an exception
try {
mIpSecService.reserveNetId();
fail("Did not throw error for all netIds reserved");
} catch (IllegalStateException expected) {
}
// Now release one and try again
int releasedNetId =
mIpSecService.TUN_INTF_NETID_START + mIpSecService.TUN_INTF_NETID_RANGE / 2;
mIpSecService.releaseNetId(releasedNetId);
assertEquals(releasedNetId, mIpSecService.reserveNetId());
}
}