BpfMapTest: add fd leak test

Test that there is no fd leak with persistent fd cache.

Bug: 236320567
Test: atest BpfMapTest#testNoFdLeaks (cached fd) [PASSED]
Test: atest BpfMapTest#testNoFdLeaks (noncached fd) [FAILED] (as expected)
[8/14] com.android.networkstack.tethering.BpfMapTest#testNoFdLeaks: FAILED (241ms)

STACKTRACE:
java.lang.AssertionError: Fd leak after 1000 iterations:  expected:<89> but was:<1089>
	at org.junit.Assert.fail(Assert.java:89)
	at org.junit.Assert.failNotEquals(Assert.java:835)
	at org.junit.Assert.assertEquals(Assert.java:647)
	at com.android.networkstack.tethering.BpfMapTest.testNoFdLeaks(BpfMapTest.java:420)

Test Code:
fd noncached BpfMap
frameworks/libs/net/common/device/com/android/net/module/util/BpfMap.java
@@ -97,7 +97,7 @@ public class BpfMap<K extends Struct, V extends Struct> implements IBpfMap<K, V>
      */
     public BpfMap(@NonNull final String path, final int flag, final Class<K> key,
             final Class<V> value) throws ErrnoException, NullPointerException {
-        mMapFd = cachedBpfFdGet(path, flag);
+        mMapFd = ParcelFileDescriptor.adoptFd(nativeBpfFdGet(path, flag));

Change-Id: I66f477fd1c291c56bccc97d385b2a554c2367b5a
This commit is contained in:
Hungming Chen
2022-07-26 22:20:27 +08:00
committed by Nucca Chen
parent 944f9e3da1
commit a81f1251dd

View File

@@ -30,6 +30,7 @@ import static org.junit.Assert.fail;
import android.net.MacAddress;
import android.os.Build;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
import android.util.ArrayMap;
@@ -42,6 +43,7 @@ import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.File;
import java.net.InetAddress;
import java.util.NoSuchElementException;
import java.util.concurrent.atomic.AtomicInteger;
@@ -393,4 +395,34 @@ public final class BpfMapTest {
assertEquals(OsConstants.ENOENT, expected.errno);
}
}
private static int getNumOpenFds() {
return new File("/proc/" + Os.getpid() + "/fd").listFiles().length;
}
@Test
public void testNoFdLeaks() throws Exception {
// Due to #setUp has called #initTestMap to open map and BpfMap is using persistent fd
// cache, expect that the fd amount is not increased in the iterations.
// See the comment of BpfMap#close.
final int iterations = 1000;
final int before = getNumOpenFds();
for (int i = 0; i < iterations; i++) {
try (BpfMap<TetherDownstream6Key, Tether6Value> map = new BpfMap<>(
TETHER_DOWNSTREAM6_FS_PATH, BpfMap.BPF_F_RDWR,
TetherDownstream6Key.class, Tether6Value.class)) {
// do nothing
}
}
final int after = getNumOpenFds();
// Check that the number of open fds is the same as before.
// If this exact match becomes flaky, we probably need to distinguish that fd is belong
// to "bpf-map".
// ex:
// $ adb shell ls -all /proc/16196/fd
// [..] network_stack 64 2022-07-26 22:01:02.300002956 +0800 749 -> anon_inode:bpf-map
// [..] network_stack 64 2022-07-26 22:01:02.188002956 +0800 75 -> anon_inode:[eventfd]
assertEquals("Fd leak after " + iterations + " iterations: ", before, after);
}
}