Add IBpfMap for injection in testing
To avoid load jni library in some testing (BpfMap load jni library
statically), add IBpfMap for injection.
Bug: 215095957
Test: atest FrameworkNetTests
Change-Id: I71e67f9cdc19a856fe5dce5940be702e866b87c4
diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp
index ea38eca..16fede8 100644
--- a/staticlibs/Android.bp
+++ b/staticlibs/Android.bp
@@ -111,6 +111,7 @@
name: "net-utils-device-common-bpf",
srcs: [
"device/com/android/net/module/util/BpfMap.java",
+ "device/com/android/net/module/util/IBpfMap.java",
"device/com/android/net/module/util/JniUtil.java",
"device/com/android/net/module/util/TcUtils.java",
],
diff --git a/staticlibs/device/com/android/net/module/util/BpfMap.java b/staticlibs/device/com/android/net/module/util/BpfMap.java
index 5f05c7c..b42c388 100644
--- a/staticlibs/device/com/android/net/module/util/BpfMap.java
+++ b/staticlibs/device/com/android/net/module/util/BpfMap.java
@@ -40,7 +40,7 @@
* @param <K> the key of the map.
* @param <V> the value of the map.
*/
-public class BpfMap<K extends Struct, V extends Struct> implements AutoCloseable {
+public class BpfMap<K extends Struct, V extends Struct> implements IBpfMap<K, V>, AutoCloseable {
static {
System.loadLibrary(JniUtil.getJniLibraryName(BpfMap.class.getPackage()));
}
@@ -100,6 +100,7 @@
* Update an existing or create a new key -> value entry in an eBbpf map.
* (use insertOrReplaceEntry() if you need to know whether insert or replace happened)
*/
+ @Override
public void updateEntry(K key, V value) throws ErrnoException {
writeToMapEntry(mMapFd, key.writeToBytes(), value.writeToBytes(), BPF_ANY);
}
@@ -108,6 +109,7 @@
* If the key does not exist in the map, insert key -> value entry into eBpf map.
* Otherwise IllegalStateException will be thrown.
*/
+ @Override
public void insertEntry(K key, V value)
throws ErrnoException, IllegalStateException {
try {
@@ -123,6 +125,7 @@
* If the key already exists in the map, replace its value. Otherwise NoSuchElementException
* will be thrown.
*/
+ @Override
public void replaceEntry(K key, V value)
throws ErrnoException, NoSuchElementException {
try {
@@ -140,6 +143,7 @@
* (use updateEntry() if you don't care whether insert or replace happened)
* Note: see inline comment below if running concurrently with delete operations.
*/
+ @Override
public boolean insertOrReplaceEntry(K key, V value)
throws ErrnoException {
try {
@@ -164,11 +168,13 @@
}
/** Remove existing key from eBpf map. Return false if map was not modified. */
+ @Override
public boolean deleteEntry(K key) throws ErrnoException {
return deleteMapEntry(mMapFd, key.writeToBytes());
}
/** Returns {@code true} if this map contains no elements. */
+ @Override
public boolean isEmpty() throws ErrnoException {
return getFirstKey() == null;
}
@@ -189,6 +195,7 @@
*
* TODO: consider allowing null passed-in key.
*/
+ @Override
public K getNextKey(@NonNull K key) throws ErrnoException {
Objects.requireNonNull(key);
return getNextKeyInternal(key);
@@ -202,11 +209,13 @@
}
/** Get the first key of eBpf map. */
+ @Override
public K getFirstKey() throws ErrnoException {
return getNextKeyInternal(null);
}
/** Check whether a key exists in the map. */
+ @Override
public boolean containsKey(@NonNull K key) throws ErrnoException {
Objects.requireNonNull(key);
@@ -215,6 +224,7 @@
}
/** Retrieve a value from the map. Return null if there is no such key. */
+ @Override
public V getValue(@NonNull K key) throws ErrnoException {
Objects.requireNonNull(key);
final byte[] rawValue = getRawValue(key.writeToBytes());
@@ -239,6 +249,7 @@
* other structural modifications to the map, such as adding entries or deleting other entries.
* Otherwise, iteration will result in undefined behaviour.
*/
+ @Override
public void forEach(BiConsumer<K, V> action) throws ErrnoException {
@Nullable K nextKey = getFirstKey();
@@ -262,6 +273,7 @@
* @throws ErrnoException if the map is already closed, if an error occurred during iteration,
* or if a non-ENOENT error occurred when deleting a key.
*/
+ @Override
public void clear() throws ErrnoException {
K key = getFirstKey();
while (key != null) {
diff --git a/staticlibs/device/com/android/net/module/util/IBpfMap.java b/staticlibs/device/com/android/net/module/util/IBpfMap.java
new file mode 100644
index 0000000..708cf61
--- /dev/null
+++ b/staticlibs/device/com/android/net/module/util/IBpfMap.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 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.net.module.util;
+
+import android.system.ErrnoException;
+
+import androidx.annotation.NonNull;
+
+import java.util.NoSuchElementException;
+import java.util.function.BiConsumer;
+
+/**
+ * The interface of BpfMap. This could be used to inject for testing.
+ * So the testing code won't load the JNI and update the entries to kernel.
+ *
+ * @param <K> the key of the map.
+ * @param <V> the value of the map.
+ */
+public interface IBpfMap<K extends Struct, V extends Struct> {
+ /** Update an existing or create a new key -> value entry in an eBbpf map. */
+ void updateEntry(K key, V value) throws ErrnoException;
+
+ /** If the key does not exist in the map, insert key -> value entry into eBpf map. */
+ void insertEntry(K key, V value) throws ErrnoException, IllegalStateException;
+
+ /** If the key already exists in the map, replace its value. */
+ void replaceEntry(K key, V value) throws ErrnoException, NoSuchElementException;
+
+ /**
+ * Update an existing or create a new key -> value entry in an eBbpf map. Returns true if
+ * inserted, false if replaced. (use updateEntry() if you don't care whether insert or replace
+ * happened).
+ */
+ boolean insertOrReplaceEntry(K key, V value) throws ErrnoException;
+
+ /** Remove existing key from eBpf map. Return true if something was deleted. */
+ boolean deleteEntry(K key) throws ErrnoException;
+
+ /** Returns {@code true} if this map contains no elements. */
+ boolean isEmpty() throws ErrnoException;
+
+ /** Get the key after the passed-in key. */
+ K getNextKey(@NonNull K key) throws ErrnoException;
+
+ /** Get the first key of the eBpf map. */
+ K getFirstKey() throws ErrnoException;
+
+ /** Check whether a key exists in the map. */
+ boolean containsKey(@NonNull K key) throws ErrnoException;
+
+ /** Retrieve a value from the map. */
+ V getValue(@NonNull K key) throws ErrnoException;
+
+ /**
+ * Iterate through the map and handle each key -> value retrieved base on the given BiConsumer.
+ */
+ void forEach(BiConsumer<K, V> action) throws ErrnoException;
+
+ /** Clears the map. */
+ void clear() throws ErrnoException;
+}