Loading packages/Tethering/Android.bp +15 −14 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ java_defaults { "netd_aidl_interface-unstable-java", "netlink-client", "networkstack-aidl-interfaces-unstable-java", "android.hardware.tetheroffload.config-V1.0-java", "android.hardware.tetheroffload.control-V1.0-java", "net-utils-framework-common", ], Loading @@ -48,25 +49,26 @@ android_library { // Due to b/143733063, APK can't access a jni lib that is in APEX (but not in the APK). cc_library { name: "libtetherutilsjni", sdk_version: "current", srcs: [ "jni/android_net_util_TetheringUtils.cpp", ], shared_libs: [ "libcgrouprc", "libnativehelper_compat_libc++", "libvndksupport", ], static_libs: [ "android.hardware.tetheroffload.config@1.0", "liblog", "libbase", "libcutils", "libhidlbase", "libjsoncpp", "libprocessgroup", "libutils", "libnativehelper_compat_libc++", ], // We cannot use plain "libc++" here to link libc++ dynamically because it results in: // java.lang.UnsatisfiedLinkError: dlopen failed: library "libc++_shared.so" not found // even if "libc++" is added into jni_libs below. Adding "libc++_shared" into jni_libs doesn't // build because soong complains of: // module Tethering missing dependencies: libc++_shared // // So, link libc++ statically. This means that we also need to ensure that all the C++ libraries // we depend on do not dynamically link libc++. This is currently the case, because liblog is // C-only and libnativehelper_compat_libc also uses stl: "c++_static". stl: "c++_static", cflags: [ "-Wall", "-Werror", Loading @@ -85,9 +87,8 @@ java_defaults { // Build system doesn't track transitive dependeicies for jni_libs, list all the dependencies // explicitly. jni_libs: [ "libcgrouprc", "liblog", "libnativehelper_compat_libc++", "libvndksupport", "libtetherutilsjni", ], resource_dirs: [ Loading packages/Tethering/jni/android_net_util_TetheringUtils.cpp +2 −108 Original line number Diff line number Diff line Loading @@ -16,123 +16,18 @@ #include <errno.h> #include <error.h> #include <hidl/HidlSupport.h> #include <jni.h> #include <nativehelper/JNIHelp.h> #include <nativehelper/ScopedUtfChars.h> #include <linux/netfilter/nfnetlink.h> #include <linux/netlink.h> #include <net/if.h> #include <netinet/icmp6.h> #include <sys/socket.h> #include <android-base/unique_fd.h> #include <android/hardware/tetheroffload/config/1.0/IOffloadConfig.h> #define LOG_TAG "TetheringUtils" #include <utils/Log.h> #include <android/log.h> namespace android { using hardware::hidl_handle; using hardware::hidl_string; using hardware::tetheroffload::config::V1_0::IOffloadConfig; namespace { inline const sockaddr * asSockaddr(const sockaddr_nl *nladdr) { return reinterpret_cast<const sockaddr *>(nladdr); } int conntrackSocket(unsigned groups) { base::unique_fd s(socket(AF_NETLINK, SOCK_DGRAM, NETLINK_NETFILTER)); if (s.get() < 0) return -errno; const struct sockaddr_nl bind_addr = { .nl_family = AF_NETLINK, .nl_pad = 0, .nl_pid = 0, .nl_groups = groups, }; if (bind(s.get(), asSockaddr(&bind_addr), sizeof(bind_addr)) != 0) { return -errno; } const struct sockaddr_nl kernel_addr = { .nl_family = AF_NETLINK, .nl_pad = 0, .nl_pid = 0, .nl_groups = groups, }; if (connect(s.get(), asSockaddr(&kernel_addr), sizeof(kernel_addr)) != 0) { return -errno; } return s.release(); } // Return a hidl_handle that owns the file descriptor owned by fd, and will // auto-close it (otherwise there would be double-close problems). // // Rely upon the compiler to eliminate the constexprs used for clarity. hidl_handle handleFromFileDescriptor(base::unique_fd fd) { hidl_handle h; static constexpr int kNumFds = 1; static constexpr int kNumInts = 0; native_handle_t *nh = native_handle_create(kNumFds, kNumInts); nh->data[0] = fd.release(); static constexpr bool kTakeOwnership = true; h.setTo(nh, kTakeOwnership); return h; } } // namespace static jboolean android_net_util_configOffload( JNIEnv* /* env */) { sp<IOffloadConfig> configInterface = IOffloadConfig::getService(); if (configInterface.get() == nullptr) { ALOGD("Could not find IOffloadConfig service."); return false; } // Per the IConfigOffload definition: // // fd1 A file descriptor bound to the following netlink groups // (NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY). // // fd2 A file descriptor bound to the following netlink groups // (NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY). base::unique_fd fd1(conntrackSocket(NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY)), fd2(conntrackSocket(NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY)); if (fd1.get() < 0 || fd2.get() < 0) { ALOGE("Unable to create conntrack handles: %d/%s", errno, strerror(errno)); return false; } hidl_handle h1(handleFromFileDescriptor(std::move(fd1))), h2(handleFromFileDescriptor(std::move(fd2))); bool rval(false); hidl_string msg; const auto status = configInterface->setHandles(h1, h2, [&rval, &msg](bool success, const hidl_string& errMsg) { rval = success; msg = errMsg; }); if (!status.isOk() || !rval) { ALOGE("IOffloadConfig::setHandles() error: '%s' / '%s'", status.description().c_str(), msg.c_str()); // If status is somehow not ok, make sure rval captures this too. rval = false; } return rval; } static void android_net_util_setupRaSocket(JNIEnv *env, jobject clazz, jobject javaFd, jint ifIndex) { Loading Loading @@ -229,7 +124,6 @@ static void android_net_util_setupRaSocket(JNIEnv *env, jobject clazz, jobject j */ static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "configOffload", "()Z", (void*) android_net_util_configOffload }, { "setupRaSocket", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_util_setupRaSocket }, }; Loading @@ -242,7 +136,7 @@ int register_android_net_util_TetheringUtils(JNIEnv* env) { extern "C" jint JNI_OnLoad(JavaVM* vm, void*) { JNIEnv *env; if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { ALOGE("ERROR: GetEnv failed"); __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "ERROR: GetEnv failed"); return JNI_ERR; } Loading packages/Tethering/src/android/net/util/TetheringUtils.java +0 −8 Original line number Diff line number Diff line Loading @@ -24,14 +24,6 @@ import java.net.SocketException; * {@hide} */ public class TetheringUtils { /** * Offload management process need to know conntrack rules to support NAT, but it may not have * permission to create netlink netfilter sockets. Create two netlink netfilter sockets and * share them with offload management process. */ public static native boolean configOffload(); /** * Configures a socket for receiving ICMPv6 router solicitations and sending advertisements. * @param fd the socket's {@link FileDescriptor}. Loading packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java +110 −3 Original line number Diff line number Diff line Loading @@ -18,19 +18,28 @@ package com.android.server.connectivity.tethering; import static android.net.util.TetheringUtils.uint16; import android.hardware.tetheroffload.config.V1_0.IOffloadConfig; import android.hardware.tetheroffload.control.V1_0.IOffloadControl; import android.hardware.tetheroffload.control.V1_0.ITetheringOffloadCallback; import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate; import android.hardware.tetheroffload.control.V1_0.NetworkProtocol; import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent; import android.net.netlink.NetlinkSocket; import android.net.util.SharedLog; import android.net.util.TetheringUtils; import android.net.util.SocketUtils; import android.os.Handler; import android.os.NativeHandle; import android.os.RemoteException; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; import com.android.internal.annotations.VisibleForTesting; import java.io.FileDescriptor; import java.io.IOException; import java.net.SocketAddress; import java.net.SocketException; import java.util.ArrayList; Loading @@ -49,6 +58,10 @@ public class OffloadHardwareInterface { private static final String NO_INTERFACE_NAME = ""; private static final String NO_IPV4_ADDRESS = ""; private static final String NO_IPV4_GATEWAY = ""; // Reference kernel/uapi/linux/netfilter/nfnetlink_compat.h private static final int NF_NETLINK_CONNTRACK_NEW = 1; private static final int NF_NETLINK_CONNTRACK_UPDATE = 2; private static final int NF_NETLINK_CONNTRACK_DESTROY = 4; private final Handler mHandler; private final SharedLog mLog; Loading Loading @@ -121,9 +134,103 @@ public class OffloadHardwareInterface { return DEFAULT_TETHER_OFFLOAD_DISABLED; } /** Configure offload management process. */ /** * Offload management process need to know conntrack rules to support NAT, but it may not have * permission to create netlink netfilter sockets. Create two netlink netfilter sockets and * share them with offload management process. */ public boolean initOffloadConfig() { return TetheringUtils.configOffload(); IOffloadConfig offloadConfig; try { offloadConfig = IOffloadConfig.getService(); } catch (RemoteException e) { mLog.e("getIOffloadConfig error " + e); return false; } if (offloadConfig == null) { mLog.e("Could not find IOffloadConfig service"); return false; } // Per the IConfigOffload definition: // // h1 provides a file descriptor bound to the following netlink groups // (NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY). // // h2 provides a file descriptor bound to the following netlink groups // (NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY). final NativeHandle h1 = createConntrackSocket( NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY); if (h1 == null) return false; final NativeHandle h2 = createConntrackSocket( NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY); if (h2 == null) { closeFdInNativeHandle(h1); return false; } final CbResults results = new CbResults(); try { offloadConfig.setHandles(h1, h2, (boolean success, String errMsg) -> { results.mSuccess = success; results.mErrMsg = errMsg; }); } catch (RemoteException e) { record("initOffloadConfig, setHandles fail", e); return false; } // Explicitly close FDs. closeFdInNativeHandle(h1); closeFdInNativeHandle(h2); record("initOffloadConfig, setHandles results:", results); return results.mSuccess; } private void closeFdInNativeHandle(final NativeHandle h) { try { h.close(); } catch (IOException | IllegalStateException e) { // IllegalStateException means fd is already closed, do nothing here. // Also nothing we can do if IOException. } } private NativeHandle createConntrackSocket(final int groups) { FileDescriptor fd; try { fd = NetlinkSocket.forProto(OsConstants.NETLINK_NETFILTER); } catch (ErrnoException e) { mLog.e("Unable to create conntrack socket " + e); return null; } final SocketAddress sockAddr = SocketUtils.makeNetlinkSocketAddress(0, groups); try { Os.bind(fd, sockAddr); } catch (ErrnoException | SocketException e) { mLog.e("Unable to bind conntrack socket for groups " + groups + " error: " + e); try { SocketUtils.closeSocket(fd); } catch (IOException ie) { // Nothing we can do here } return null; } try { Os.connect(fd, sockAddr); } catch (ErrnoException | SocketException e) { mLog.e("connect to kernel fail for groups " + groups + " error: " + e); try { SocketUtils.closeSocket(fd); } catch (IOException ie) { // Nothing we can do here } return null; } return new NativeHandle(fd, true); } /** Initialize the tethering offload HAL. */ Loading Loading
packages/Tethering/Android.bp +15 −14 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ java_defaults { "netd_aidl_interface-unstable-java", "netlink-client", "networkstack-aidl-interfaces-unstable-java", "android.hardware.tetheroffload.config-V1.0-java", "android.hardware.tetheroffload.control-V1.0-java", "net-utils-framework-common", ], Loading @@ -48,25 +49,26 @@ android_library { // Due to b/143733063, APK can't access a jni lib that is in APEX (but not in the APK). cc_library { name: "libtetherutilsjni", sdk_version: "current", srcs: [ "jni/android_net_util_TetheringUtils.cpp", ], shared_libs: [ "libcgrouprc", "libnativehelper_compat_libc++", "libvndksupport", ], static_libs: [ "android.hardware.tetheroffload.config@1.0", "liblog", "libbase", "libcutils", "libhidlbase", "libjsoncpp", "libprocessgroup", "libutils", "libnativehelper_compat_libc++", ], // We cannot use plain "libc++" here to link libc++ dynamically because it results in: // java.lang.UnsatisfiedLinkError: dlopen failed: library "libc++_shared.so" not found // even if "libc++" is added into jni_libs below. Adding "libc++_shared" into jni_libs doesn't // build because soong complains of: // module Tethering missing dependencies: libc++_shared // // So, link libc++ statically. This means that we also need to ensure that all the C++ libraries // we depend on do not dynamically link libc++. This is currently the case, because liblog is // C-only and libnativehelper_compat_libc also uses stl: "c++_static". stl: "c++_static", cflags: [ "-Wall", "-Werror", Loading @@ -85,9 +87,8 @@ java_defaults { // Build system doesn't track transitive dependeicies for jni_libs, list all the dependencies // explicitly. jni_libs: [ "libcgrouprc", "liblog", "libnativehelper_compat_libc++", "libvndksupport", "libtetherutilsjni", ], resource_dirs: [ Loading
packages/Tethering/jni/android_net_util_TetheringUtils.cpp +2 −108 Original line number Diff line number Diff line Loading @@ -16,123 +16,18 @@ #include <errno.h> #include <error.h> #include <hidl/HidlSupport.h> #include <jni.h> #include <nativehelper/JNIHelp.h> #include <nativehelper/ScopedUtfChars.h> #include <linux/netfilter/nfnetlink.h> #include <linux/netlink.h> #include <net/if.h> #include <netinet/icmp6.h> #include <sys/socket.h> #include <android-base/unique_fd.h> #include <android/hardware/tetheroffload/config/1.0/IOffloadConfig.h> #define LOG_TAG "TetheringUtils" #include <utils/Log.h> #include <android/log.h> namespace android { using hardware::hidl_handle; using hardware::hidl_string; using hardware::tetheroffload::config::V1_0::IOffloadConfig; namespace { inline const sockaddr * asSockaddr(const sockaddr_nl *nladdr) { return reinterpret_cast<const sockaddr *>(nladdr); } int conntrackSocket(unsigned groups) { base::unique_fd s(socket(AF_NETLINK, SOCK_DGRAM, NETLINK_NETFILTER)); if (s.get() < 0) return -errno; const struct sockaddr_nl bind_addr = { .nl_family = AF_NETLINK, .nl_pad = 0, .nl_pid = 0, .nl_groups = groups, }; if (bind(s.get(), asSockaddr(&bind_addr), sizeof(bind_addr)) != 0) { return -errno; } const struct sockaddr_nl kernel_addr = { .nl_family = AF_NETLINK, .nl_pad = 0, .nl_pid = 0, .nl_groups = groups, }; if (connect(s.get(), asSockaddr(&kernel_addr), sizeof(kernel_addr)) != 0) { return -errno; } return s.release(); } // Return a hidl_handle that owns the file descriptor owned by fd, and will // auto-close it (otherwise there would be double-close problems). // // Rely upon the compiler to eliminate the constexprs used for clarity. hidl_handle handleFromFileDescriptor(base::unique_fd fd) { hidl_handle h; static constexpr int kNumFds = 1; static constexpr int kNumInts = 0; native_handle_t *nh = native_handle_create(kNumFds, kNumInts); nh->data[0] = fd.release(); static constexpr bool kTakeOwnership = true; h.setTo(nh, kTakeOwnership); return h; } } // namespace static jboolean android_net_util_configOffload( JNIEnv* /* env */) { sp<IOffloadConfig> configInterface = IOffloadConfig::getService(); if (configInterface.get() == nullptr) { ALOGD("Could not find IOffloadConfig service."); return false; } // Per the IConfigOffload definition: // // fd1 A file descriptor bound to the following netlink groups // (NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY). // // fd2 A file descriptor bound to the following netlink groups // (NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY). base::unique_fd fd1(conntrackSocket(NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY)), fd2(conntrackSocket(NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY)); if (fd1.get() < 0 || fd2.get() < 0) { ALOGE("Unable to create conntrack handles: %d/%s", errno, strerror(errno)); return false; } hidl_handle h1(handleFromFileDescriptor(std::move(fd1))), h2(handleFromFileDescriptor(std::move(fd2))); bool rval(false); hidl_string msg; const auto status = configInterface->setHandles(h1, h2, [&rval, &msg](bool success, const hidl_string& errMsg) { rval = success; msg = errMsg; }); if (!status.isOk() || !rval) { ALOGE("IOffloadConfig::setHandles() error: '%s' / '%s'", status.description().c_str(), msg.c_str()); // If status is somehow not ok, make sure rval captures this too. rval = false; } return rval; } static void android_net_util_setupRaSocket(JNIEnv *env, jobject clazz, jobject javaFd, jint ifIndex) { Loading Loading @@ -229,7 +124,6 @@ static void android_net_util_setupRaSocket(JNIEnv *env, jobject clazz, jobject j */ static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "configOffload", "()Z", (void*) android_net_util_configOffload }, { "setupRaSocket", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_util_setupRaSocket }, }; Loading @@ -242,7 +136,7 @@ int register_android_net_util_TetheringUtils(JNIEnv* env) { extern "C" jint JNI_OnLoad(JavaVM* vm, void*) { JNIEnv *env; if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { ALOGE("ERROR: GetEnv failed"); __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "ERROR: GetEnv failed"); return JNI_ERR; } Loading
packages/Tethering/src/android/net/util/TetheringUtils.java +0 −8 Original line number Diff line number Diff line Loading @@ -24,14 +24,6 @@ import java.net.SocketException; * {@hide} */ public class TetheringUtils { /** * Offload management process need to know conntrack rules to support NAT, but it may not have * permission to create netlink netfilter sockets. Create two netlink netfilter sockets and * share them with offload management process. */ public static native boolean configOffload(); /** * Configures a socket for receiving ICMPv6 router solicitations and sending advertisements. * @param fd the socket's {@link FileDescriptor}. Loading
packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java +110 −3 Original line number Diff line number Diff line Loading @@ -18,19 +18,28 @@ package com.android.server.connectivity.tethering; import static android.net.util.TetheringUtils.uint16; import android.hardware.tetheroffload.config.V1_0.IOffloadConfig; import android.hardware.tetheroffload.control.V1_0.IOffloadControl; import android.hardware.tetheroffload.control.V1_0.ITetheringOffloadCallback; import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate; import android.hardware.tetheroffload.control.V1_0.NetworkProtocol; import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent; import android.net.netlink.NetlinkSocket; import android.net.util.SharedLog; import android.net.util.TetheringUtils; import android.net.util.SocketUtils; import android.os.Handler; import android.os.NativeHandle; import android.os.RemoteException; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; import com.android.internal.annotations.VisibleForTesting; import java.io.FileDescriptor; import java.io.IOException; import java.net.SocketAddress; import java.net.SocketException; import java.util.ArrayList; Loading @@ -49,6 +58,10 @@ public class OffloadHardwareInterface { private static final String NO_INTERFACE_NAME = ""; private static final String NO_IPV4_ADDRESS = ""; private static final String NO_IPV4_GATEWAY = ""; // Reference kernel/uapi/linux/netfilter/nfnetlink_compat.h private static final int NF_NETLINK_CONNTRACK_NEW = 1; private static final int NF_NETLINK_CONNTRACK_UPDATE = 2; private static final int NF_NETLINK_CONNTRACK_DESTROY = 4; private final Handler mHandler; private final SharedLog mLog; Loading Loading @@ -121,9 +134,103 @@ public class OffloadHardwareInterface { return DEFAULT_TETHER_OFFLOAD_DISABLED; } /** Configure offload management process. */ /** * Offload management process need to know conntrack rules to support NAT, but it may not have * permission to create netlink netfilter sockets. Create two netlink netfilter sockets and * share them with offload management process. */ public boolean initOffloadConfig() { return TetheringUtils.configOffload(); IOffloadConfig offloadConfig; try { offloadConfig = IOffloadConfig.getService(); } catch (RemoteException e) { mLog.e("getIOffloadConfig error " + e); return false; } if (offloadConfig == null) { mLog.e("Could not find IOffloadConfig service"); return false; } // Per the IConfigOffload definition: // // h1 provides a file descriptor bound to the following netlink groups // (NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY). // // h2 provides a file descriptor bound to the following netlink groups // (NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY). final NativeHandle h1 = createConntrackSocket( NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY); if (h1 == null) return false; final NativeHandle h2 = createConntrackSocket( NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY); if (h2 == null) { closeFdInNativeHandle(h1); return false; } final CbResults results = new CbResults(); try { offloadConfig.setHandles(h1, h2, (boolean success, String errMsg) -> { results.mSuccess = success; results.mErrMsg = errMsg; }); } catch (RemoteException e) { record("initOffloadConfig, setHandles fail", e); return false; } // Explicitly close FDs. closeFdInNativeHandle(h1); closeFdInNativeHandle(h2); record("initOffloadConfig, setHandles results:", results); return results.mSuccess; } private void closeFdInNativeHandle(final NativeHandle h) { try { h.close(); } catch (IOException | IllegalStateException e) { // IllegalStateException means fd is already closed, do nothing here. // Also nothing we can do if IOException. } } private NativeHandle createConntrackSocket(final int groups) { FileDescriptor fd; try { fd = NetlinkSocket.forProto(OsConstants.NETLINK_NETFILTER); } catch (ErrnoException e) { mLog.e("Unable to create conntrack socket " + e); return null; } final SocketAddress sockAddr = SocketUtils.makeNetlinkSocketAddress(0, groups); try { Os.bind(fd, sockAddr); } catch (ErrnoException | SocketException e) { mLog.e("Unable to bind conntrack socket for groups " + groups + " error: " + e); try { SocketUtils.closeSocket(fd); } catch (IOException ie) { // Nothing we can do here } return null; } try { Os.connect(fd, sockAddr); } catch (ErrnoException | SocketException e) { mLog.e("connect to kernel fail for groups " + groups + " error: " + e); try { SocketUtils.closeSocket(fd); } catch (IOException ie) { // Nothing we can do here } return null; } return new NativeHandle(fd, true); } /** Initialize the tethering offload HAL. */ Loading