diff --git a/Tethering/Android.bp b/Tethering/Android.bp index 2a39028318..b7c720929c 100644 --- a/Tethering/Android.bp +++ b/Tethering/Android.bp @@ -167,6 +167,30 @@ cc_library { ldflags: ["-Wl,--exclude-libs=ALL,--error-limit=0"], } +cc_library_shared { + name: "libcom_android_networkstack_tethering_util_jni_CommonConnectivityJni", + srcs: [ + "jni/commonconnectivity/onload.cpp", + ], + min_sdk_version: "30", + shared_libs: [ + "liblog", + "libnativehelper", + ], + static_libs: [ + "libcommonconnectivityjni", + ], + cflags: [ + "-Wall", + "-Werror", + "-Wno-unused-parameter", + "-Wthread-safety", + ], + apex_available: [ + "com.android.tethering", + ], +} + // Common defaults for compiling the actual APK. java_defaults { name: "TetheringAppDefaults", diff --git a/Tethering/apex/Android.bp b/Tethering/apex/Android.bp index 19e2c6f078..7329396163 100644 --- a/Tethering/apex/Android.bp +++ b/Tethering/apex/Android.bp @@ -67,6 +67,7 @@ apex { "libservice-connectivity", "libservice-thread-jni", "libandroid_net_connectivity_com_android_net_module_util_jni", + "libandroid_net_connectivity_com_android_net_module_util_jni_CommonConnectivityJni", ], native_shared_libs: [ "libcom.android.tethering.dns_helper", diff --git a/Tethering/jni/commonconnectivity/onload.cpp b/Tethering/jni/commonconnectivity/onload.cpp new file mode 100644 index 0000000000..b1fb6d7d91 --- /dev/null +++ b/Tethering/jni/commonconnectivity/onload.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2025 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. + */ +#define LOG_TAG "com_android_networkstack_tethering_util_CommonConnectivityJni" + +#include +#include + +namespace android { +int register_CommonConnectivityJni(JNIEnv *env, char const *class_name); + +extern "C" jint JNI_OnLoad(JavaVM *vm, void *) { + JNIEnv *env; + if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != + JNI_OK) { + __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "ERROR: GetEnv failed"); + return JNI_ERR; + } + + if (register_CommonConnectivityJni(env, + "com/android/networkstack/tethering/util/CommonConnectivityJni") < 0) return JNI_ERR; + + return JNI_VERSION_1_6; +} +}; // namespace android \ No newline at end of file diff --git a/service/Android.bp b/service/Android.bp index 62fe9fd516..a98e71c0b1 100644 --- a/service/Android.bp +++ b/service/Android.bp @@ -100,6 +100,30 @@ cc_library_shared { ], } +cc_library_shared { + name: "libandroid_net_connectivity_com_android_net_module_util_jni_CommonConnectivityJni", + srcs: [ + "jni/commonconnectivity/onload.cpp", + ], + min_sdk_version: "30", + shared_libs: [ + "liblog", + "libnativehelper", + ], + static_libs: [ + "libcommonconnectivityjni", + ], + cflags: [ + "-Wall", + "-Werror", + "-Wno-unused-parameter", + "-Wthread-safety", + ], + apex_available: [ + "com.android.tethering", + ], +} + cc_library_shared { name: "libservice-connectivity", min_sdk_version: "30", @@ -126,6 +150,7 @@ cc_library_shared { "libnet_utils_device_common_bpfjni", "libserviceconnectivityjni", "netd_aidl_interface-lateststable-ndk", + "libcommonconnectivityjni", ], shared_libs: [ "libbase", diff --git a/service/jni/commonconnectivity/onload.cpp b/service/jni/commonconnectivity/onload.cpp new file mode 100644 index 0000000000..5810cf7cf8 --- /dev/null +++ b/service/jni/commonconnectivity/onload.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2025 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. + */ +#define LOG_TAG "android_net_connectivity_com_android_net_module_util_CommonConnectivityJni" + +#include +#include + +namespace android { +int register_CommonConnectivityJni(JNIEnv *env, char const *class_name); + +extern "C" jint JNI_OnLoad(JavaVM *vm, void *) { + JNIEnv *env; + if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) { + __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "ERROR: GetEnv failed"); + return JNI_ERR; + } + + if (register_CommonConnectivityJni( + env, + "android/net/connectivity/com/android/net/module/util/CommonConnectivityJni" + ) < 0) { + return JNI_ERR; + } + + return JNI_VERSION_1_6; +} +}; // namespace android \ No newline at end of file diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 25ce3013fa..bc1aa4cd5e 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -87,6 +87,10 @@ java_library { srcs: [ "device/com/android/net/module/util/ProcfsParsingUtils.java", "device/com/android/net/module/util/dhcp6/*.java", + "device/com/android/net/module/util/CommonConnectivityJni.java", + "device/com/android/net/module/util/RealtimeScheduler.java", + "device/com/android/net/module/util/TimerFdUtils.java", + "device/com/android/net/module/util/JniUtil.java", "framework/com/android/net/module/util/HexDump.java", ], sdk_version: "module_current", diff --git a/staticlibs/device/com/android/net/module/util/CommonConnectivityJni.java b/staticlibs/device/com/android/net/module/util/CommonConnectivityJni.java new file mode 100644 index 0000000000..644aac394c --- /dev/null +++ b/staticlibs/device/com/android/net/module/util/CommonConnectivityJni.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2025 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; + +/** + * Contains JNI functions for use in + * ConnectivityService module + * - libandroid_net_connectivity_com_android_net_module_util_jni_CommonConnectivityJni + * Tethering apex + * - libcom_android_networkstack_tethering_util_jni_CommonConnectivityJni + * NetworkStack module + * - libcom_android_networkstack_com_android_net_module_util_jni_CommonConnectivityJni + */ +public class CommonConnectivityJni { + static { + final String libName = + JniUtil.getJniLibraryName(CommonConnectivityJni.class); + System.loadLibrary(libName); + } + + /** + * Create a timerfd. + * + * @throws ErrnoException if the timerfd creation is failed. + */ + public static native int createTimerFd() throws ErrnoException; + + /** + * Set given time to the timerfd. + * + * @param timeMs target time + * @throws ErrnoException if setting expiration time is failed. + */ + public static native void setTimerFdTime(int fd, long timeMs) throws ErrnoException; +} diff --git a/staticlibs/device/com/android/net/module/util/JniUtil.java b/staticlibs/device/com/android/net/module/util/JniUtil.java index 5210a3ef0e..cd2678b9b5 100644 --- a/staticlibs/device/com/android/net/module/util/JniUtil.java +++ b/staticlibs/device/com/android/net/module/util/JniUtil.java @@ -32,4 +32,18 @@ public final class JniUtil { return libPrefix + "_jni"; } + + /** + * The method to find jni library accroding to the giving class name. + * + * The jni library name would be packageName + _jni_ + className .so. E.g. + * com_android_networkstack_tethering_util_jni_CommonConnectivityJni + * for tethering. + * android_net_connectivity_com_android_net_module_util_jni_CommonConnectivityJni + * for connectivity, + * + */ + public static String getJniLibraryName(final Class cls) { + return getJniLibraryName(cls.getPackage()) + "_" + cls.getSimpleName(); + } } diff --git a/staticlibs/device/com/android/net/module/util/TimerFdUtils.java b/staticlibs/device/com/android/net/module/util/TimerFdUtils.java index cce7efd816..8b8373f045 100644 --- a/staticlibs/device/com/android/net/module/util/TimerFdUtils.java +++ b/staticlibs/device/com/android/net/module/util/TimerFdUtils.java @@ -30,7 +30,7 @@ public class TimerFdUtils { */ static int createTimerFileDescriptor() { try { - return ServiceConnectivityJni.createTimerFd(); + return CommonConnectivityJni.createTimerFd(); } catch (ErrnoException e) { Log.e(TAG, "createTimerFd failed", e); return -1; @@ -42,7 +42,7 @@ public class TimerFdUtils { */ static boolean setExpirationTime(int fd, long expirationTimeMs) { try { - ServiceConnectivityJni.setTimerFdTime(fd, expirationTimeMs); + CommonConnectivityJni.setTimerFdTime(fd, expirationTimeMs); } catch (ErrnoException e) { Log.e(TAG, "setExpirationTime failed", e); return false; diff --git a/staticlibs/native/commonconnectivityjni/Android.bp b/staticlibs/native/commonconnectivityjni/Android.bp new file mode 100644 index 0000000000..79465e6164 --- /dev/null +++ b/staticlibs/native/commonconnectivityjni/Android.bp @@ -0,0 +1,48 @@ +// Copyright (C) 2025 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 { + default_team: "trendy_team_fwk_core_networking", + default_applicable_licenses: ["Android-Apache-2.0"], +} + +cc_library_static { + name: "libcommonconnectivityjni", + srcs: [ + "com_android_net_module_util_CommonConnectivityJni.cpp", + ], + header_libs: [ + "jni_headers", + ], + shared_libs: [ + "liblog", + "libnativehelper_compat_libc++", + ], + stl: "libc++_static", + cflags: [ + "-Wall", + "-Werror", + "-Wno-unused-parameter", + ], + sdk_version: "current", + min_sdk_version: "30", + apex_available: [ + "com.android.tethering", + "//apex_available:platform", + ], + visibility: [ + "//packages/modules/Connectivity:__subpackages__", + "//packages/modules/NetworkStack:__subpackages__", + ], +} diff --git a/staticlibs/native/commonconnectivityjni/com_android_net_module_util_CommonConnectivityJni.cpp b/staticlibs/native/commonconnectivityjni/com_android_net_module_util_CommonConnectivityJni.cpp new file mode 100644 index 0000000000..557e55866d --- /dev/null +++ b/staticlibs/native/commonconnectivityjni/com_android_net_module_util_CommonConnectivityJni.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2025 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. + */ +#include + +#include + +#define MSEC_PER_SEC 1000 +#define NSEC_PER_MSEC 1000000 + +namespace android { + +static jint createTimerFd(JNIEnv *env, jclass clazz) { + int tfd; + // For safety, the file descriptor should have O_NONBLOCK(TFD_NONBLOCK) set + // using fcntl during creation. This ensures that, in the worst-case + // scenario, an EAGAIN error is returned when reading. + tfd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK); + if (tfd == -1) { + jniThrowErrnoException(env, "createTimerFd", tfd); + } + return tfd; +} + +static void setTimerFdTime(JNIEnv *env, jclass clazz, jint tfd, + jlong milliseconds) { + struct itimerspec new_value; + new_value.it_value.tv_sec = milliseconds / MSEC_PER_SEC; + new_value.it_value.tv_nsec = (milliseconds % MSEC_PER_SEC) * NSEC_PER_MSEC; + // Set the interval time to 0 because it's designed for repeated timer + // expirations after the initial expiration, which doesn't fit the current + // usage. + new_value.it_interval.tv_sec = 0; + new_value.it_interval.tv_nsec = 0; + + int ret = timerfd_settime(tfd, 0, &new_value, NULL); + if (ret == -1) { + jniThrowErrnoException(env, "setTimerFdTime", ret); + } +} + +//------------------------------------------------------------------------------ + +/* + * JNI registration. + */ +static const JNINativeMethod gMethods[] = { + /* name, signature, funcPtr */ + {"createTimerFd", "()I", (void *)createTimerFd}, + {"setTimerFdTime", "(IJ)V", (void *)setTimerFdTime}, +}; + +int register_CommonConnectivityJni(JNIEnv *env, char const *class_name) { + return jniRegisterNativeMethods(env, class_name, gMethods, NELEM(gMethods)); +} + +} // namespace android diff --git a/staticlibs/native/serviceconnectivityjni/com_android_net_module_util_ServiceConnectivityJni.cpp b/staticlibs/native/serviceconnectivityjni/com_android_net_module_util_ServiceConnectivityJni.cpp index 7e9b35029b..3f152ef33f 100644 --- a/staticlibs/native/serviceconnectivityjni/com_android_net_module_util_ServiceConnectivityJni.cpp +++ b/staticlibs/native/serviceconnectivityjni/com_android_net_module_util_ServiceConnectivityJni.cpp @@ -52,35 +52,6 @@ namespace android { -static jint createTimerFd(JNIEnv *env, jclass clazz) { - int tfd; - // For safety, the file descriptor should have O_NONBLOCK(TFD_NONBLOCK) set - // using fcntl during creation. This ensures that, in the worst-case scenario, - // an EAGAIN error is returned when reading. - tfd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK); - if (tfd == -1) { - jniThrowErrnoException(env, "createTimerFd", tfd); - } - return tfd; -} - -static void setTimerFdTime(JNIEnv *env, jclass clazz, jint tfd, - jlong milliseconds) { - struct itimerspec new_value; - new_value.it_value.tv_sec = milliseconds / MSEC_PER_SEC; - new_value.it_value.tv_nsec = (milliseconds % MSEC_PER_SEC) * NSEC_PER_MSEC; - // Set the interval time to 0 because it's designed for repeated timer - // expirations after the initial expiration, which doesn't fit the current - // usage. - new_value.it_interval.tv_sec = 0; - new_value.it_interval.tv_nsec = 0; - - int ret = timerfd_settime(tfd, 0, &new_value, NULL); - if (ret == -1) { - jniThrowErrnoException(env, "setTimerFdTime", ret); - } -} - static jstring getDriverNameForInterface(JNIEnv *env, jclass clazz, jstring jifname) { base::unique_fd fd(socket(AF_INET6, SOCK_DGRAM, 0)); if (!fd.ok()) { @@ -219,8 +190,6 @@ static void bringUpInterface(JNIEnv *env, jclass /* clazz */, jstring jIface) { */ static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ - {"createTimerFd", "()I", (void *)createTimerFd}, - {"setTimerFdTime", "(IJ)V", (void *)setTimerFdTime}, {"getDriverNameForInterface", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getDriverNameForInterface}, {"setTunTapCarrierEnabled", "(Ljava/lang/String;IZ)V", diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/JniUtilTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/JniUtilTest.kt index 7574087780..121e8603dc 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/JniUtilTest.kt +++ b/staticlibs/tests/unit/src/com/android/net/module/util/JniUtilTest.kt @@ -30,9 +30,25 @@ public final class JniUtilTest { @Test fun testGetJniLibraryName() { - assertEquals(TEST_JAVA_UTIL_NAME, - JniUtil.getJniLibraryName(java.util.Set::class.java.getPackage())) - assertEquals(TEST_ORG_JUNIT_NAME, - JniUtil.getJniLibraryName(org.junit.Before::class.java.getPackage())) + assertEquals( + TEST_JAVA_UTIL_NAME, + JniUtil.getJniLibraryName(java.util.Set::class.java.getPackage()) + ) + assertEquals( + TEST_ORG_JUNIT_NAME, + JniUtil.getJniLibraryName(org.junit.Before::class.java.getPackage()) + ) + } + + @Test + fun testGetJniLibraryNameForClass() { + assertEquals( + "java_util_jni_Set", + JniUtil.getJniLibraryName(java.util.Set::class.java) + ) + assertEquals( + "org_junit_jni_Before", + JniUtil.getJniLibraryName(org.junit.Before::class.java) + ) } } diff --git a/tests/common/Android.bp b/tests/common/Android.bp index 888c12ad6c..2c37494f3b 100644 --- a/tests/common/Android.bp +++ b/tests/common/Android.bp @@ -122,6 +122,7 @@ android_test { // For NetworkStackUtils included in NetworkStackBase "libnetworkstackutilsjni", "libandroid_net_connectivity_com_android_net_module_util_jni", + "libandroid_net_connectivity_com_android_net_module_util_jni_CommonConnectivityJni", "libcom_android_networkstack_tethering_util_jni", // For framework tests "libservice-connectivity", diff --git a/tests/integration/Android.bp b/tests/integration/Android.bp index b9f67e1181..b50296a498 100644 --- a/tests/integration/Android.bp +++ b/tests/integration/Android.bp @@ -67,6 +67,7 @@ android_test { "libnativehelper_compat_libc++", "libnetworkstackutilsjni", "libandroid_net_connectivity_com_android_net_module_util_jni", + "libandroid_net_connectivity_com_android_net_module_util_jni_CommonConnectivityJni", "libservice-connectivity", ], jarjar_rules: ":connectivity-jarjar-rules", diff --git a/tests/unit/Android.bp b/tests/unit/Android.bp index 9edf9bd355..28d01c5935 100644 --- a/tests/unit/Android.bp +++ b/tests/unit/Android.bp @@ -171,6 +171,7 @@ android_test { ], jni_libs: [ "libandroid_net_connectivity_com_android_net_module_util_jni", + "libandroid_net_connectivity_com_android_net_module_util_jni_CommonConnectivityJni", "libservice-connectivity", ], }