From 2afef5070ab8c6cf8deff8ca5f0dd87d018f5d91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Tue, 12 Aug 2025 13:28:10 -0700 Subject: [PATCH] Optimize BpfMap JNI calls with FastNative/CriticalNative annotations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert BpfMap native methods to use @FastNative to reduce JNI overhead. Refactor synchronizeKernelRCU() to be @CriticalNative for maximum performance by changing its error handling to return an error code instead of throwing directly from native code. (In practice we don't expect it to *ever* fail) FYI: @FastNative and @CriticalNative are Android-specific annotations that signal to the ART runtime to use a lower-overhead JNI transition, resulting in better performance. A standard JNI call tells the Garbage Collector (GC) that the thread is transitioning to a 'Native' state. This is a signal to the GC that the thread might be busy for a while and shouldn't be suspended arbitrarily. @FastNative is for short, quick functions: This provides a moderately faster JNI call (thread is still 'Runnable'). The native function signature remains the same as a standard JNI method, and it can still access the JNIEnv* to interact with Java objects or throw exceptions. @CriticalNative is for short, quick & trivial functions: This provides the fastest possible JNI transition and is intended for simple, performance-critical leaf functions. It comes with strict requirements: - The native method cannot throw exceptions, create Java objects, or make any other JNI calls. - All arguments and the return type must be primitive, ie: jboolean [bool] jbyte [s8] jchar [u16] jshort [s16] jint [s32] jlong [s64] jfloat [32-bit] jdouble [64-bit] void Java objects like String or byte[] are not allowed. Because of these restrictions, the native C++ function signature must not include JNIEnv* or jobject/jclass parameters. (This likely also means it must be 'static') Test: TreeHugger Flag: EXEMPT mainline Signed-off-by: Maciej Żenczykowski Change-Id: I9b6107b26086df2e87218ff9274593e9f2eb6b0b --- .../com/android/net/module/util/BpfMap.java | 17 +++++++++++++-- .../com_android_net_module_util_BpfMap.cpp | 21 +++++++------------ 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/staticlibs/device/com/android/net/module/util/BpfMap.java b/staticlibs/device/com/android/net/module/util/BpfMap.java index a3f12c1bdd..da04c732dd 100644 --- a/staticlibs/device/com/android/net/module/util/BpfMap.java +++ b/staticlibs/device/com/android/net/module/util/BpfMap.java @@ -28,6 +28,9 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; +import dalvik.annotation.optimization.CriticalNative; +import dalvik.annotation.optimization.FastNative; + import java.util.NoSuchElementException; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; @@ -262,9 +265,14 @@ public class BpfMap implements IBpfMap /** Synchronize Kernel RCU */ public static void synchronizeKernelRCU() throws ErrnoException { - nativeSynchronizeKernelRCU(); + final int err = nativeSynchronizeKernelRCU(); + if (err != 0) { + final int errno = -err; + throw new ErrnoException("nativeSynchronizeKernelRCU", errno); + } } + @FastNative private static native int nativeBpfFdGet(String path, int mode, int keySize, int valueSize) throws ErrnoException, NullPointerException; @@ -273,19 +281,24 @@ public class BpfMap implements IBpfMap // the object from being garbage collected (and thus potentially maps closed) prior // to the native code actually running (with a possibly already closed fd). + @FastNative private native void nativeWriteToMapEntry(int fd, byte[] key, byte[] value, int flags) throws ErrnoException; + @FastNative private native boolean nativeDeleteMapEntry(int fd, byte[] key) throws ErrnoException; // If key is found, the operation returns true and the nextKey would reference to the next // element. If key is not found, the operation returns true and the nextKey would reference to // the first element. If key is the last element, false is returned. + @FastNative private native boolean nativeGetNextMapKey(int fd, byte[] key, byte[] nextKey) throws ErrnoException; + @FastNative private native boolean nativeFindMapEntry(int fd, byte[] key, byte[] value) throws ErrnoException; - private static native void nativeSynchronizeKernelRCU() throws ErrnoException; + @CriticalNative + private static native int nativeSynchronizeKernelRCU(); } diff --git a/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp b/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp index d862f6b371..38cc92c1e1 100644 --- a/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp +++ b/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp @@ -135,20 +135,12 @@ static jboolean com_android_net_module_util_BpfMap_nativeFindMapEntry(JNIEnv *en return throwIfNotEnoent(env, "nativeFindMapEntry", ret, errno); } -static void com_android_net_module_util_BpfMap_nativeSynchronizeKernelRCU(JNIEnv *env, - jclass clazz) { +static jint com_android_net_module_util_BpfMap_nativeSynchronizeKernelRCU() { const int pfSocket = socket(AF_KEY, SOCK_RAW | SOCK_CLOEXEC, PF_KEY_V2); - - if (pfSocket < 0) { - jniThrowErrnoException(env, "nativeSynchronizeKernelRCU:socket", errno); - return; - } - - if (close(pfSocket)) { - jniThrowErrnoException(env, "nativeSynchronizeKernelRCU:close", errno); - return; - } - return; + if (pfSocket < 0) return -errno; + // On Linux close() will always close the fd, any error it returns is a previous pending error. + if (close(pfSocket)) return -errno; // in practice cannot fail + return 0; } /* @@ -166,7 +158,8 @@ static const JNINativeMethod gMethods[] = { (void*) com_android_net_module_util_BpfMap_nativeGetNextMapKey }, { "nativeFindMapEntry", "(I[B[B)Z", (void*) com_android_net_module_util_BpfMap_nativeFindMapEntry }, - { "nativeSynchronizeKernelRCU", "()V", + // CriticalNative + { "nativeSynchronizeKernelRCU", "()I", (void*) com_android_net_module_util_BpfMap_nativeSynchronizeKernelRCU }, };