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;
+}