Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7f03c094 authored by Remi NGUYEN VAN's avatar Remi NGUYEN VAN Committed by Gerrit Code Review
Browse files

Merge "Remove dependency on legacy jniGetFDFromFileDescriptor"

parents 064bbb49 0c455664
Loading
Loading
Loading
Loading
+65 −5
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

#define LOG_TAG "NetworkStackUtils-JNI"

#include <dlfcn.h>
#include <errno.h>
#include <jni.h>
#include <linux/filter.h>
@@ -27,11 +28,11 @@
#include <netinet/ip6.h>
#include <netinet/udp.h>
#include <stdlib.h>
#include <sys/system_properties.h>

#include <string>

#include <nativehelper/JNIHelp.h>
#include <nativehelper/JNIHelpCompat.h>

#include <android/log.h>

@@ -57,6 +58,65 @@ static bool checkLenAndCopy(JNIEnv* env, const jbyteArray& addr, int len, void*
    return true;
}

static int getNativeFileDescriptorWithoutNdk(JNIEnv* env, jobject javaFd) {
    // Prior to Android S, we need to find the descriptor field in the FileDescriptor class. The
    // symbol name has been stable in libcore, but is a private implementation detail.
    static jfieldID descriptorFieldID = nullptr;
    if (descriptorFieldID == nullptr) {
        jclass fileDescriptorClass = env->FindClass("java/io/FileDescriptor");
        descriptorFieldID = env->GetFieldID(fileDescriptorClass, "descriptor", "I");
        env->DeleteLocalRef(fileDescriptorClass);
        if (descriptorFieldID == nullptr) {
            __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "Failed to get descriptor field.");
            return -1;
        }
    }
    return javaFd != nullptr ? env->GetIntField(javaFd, descriptorFieldID) : -1;
}

static int getNativeFileDescriptorWithNdk(JNIEnv* env, jobject javaFd) {
    // Since Android S, there is an NDK API to get a file descriptor present in libnativehelper.so.
    // libnativehelper is loaded into all processes by the zygote since the zygote uses it
    // to load the Android Runtime and is also a public library (because of the NDK API).
    static int (*ndkGetFD)(JNIEnv*, jobject) = nullptr;
    if (ndkGetFD == nullptr) {
        void* handle = dlopen("libnativehelper.so", RTLD_NOLOAD | RTLD_NODELETE);
        ndkGetFD = reinterpret_cast<decltype(ndkGetFD)>(dlsym(handle, "AFileDescriptor_getFD"));
        if (ndkGetFD == nullptr) {
            __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
                                "Failed to dlsym(AFileDescriptor_getFD): %s", dlerror());
            dlclose(handle);
            return -1;
        }
        dlclose(handle);
    }
    return javaFd != nullptr ? ndkGetFD(env, javaFd) : -1;
}

static int getNativeFileDescriptor(JNIEnv* env, jobject javaFd) {
    static bool preferNdkFileDescriptorApi = false;
    static bool probeNdkFileDescriptorApi = true;

    if (probeNdkFileDescriptorApi) {
        // Check if we should use the NDK File Descriptor API introduced in S.
        preferNdkFileDescriptorApi = (android_get_device_api_level() >= __ANDROID_API_S__);
        if (!preferNdkFileDescriptorApi) {
            // Check if this is a device with Android S dogfood build.
            static constexpr const char* kCodenameProperty = "ro.build.version.codename";
            char codename[PROP_VALUE_MAX] = { 0 };
            preferNdkFileDescriptorApi = (__system_property_get(kCodenameProperty, codename) > 0 &&
                                          strncmp(codename, "S", 2) == 0);
        }
        probeNdkFileDescriptorApi = false;
    }

    if (preferNdkFileDescriptorApi) {
        return getNativeFileDescriptorWithNdk(env, javaFd);
    } else {
        return getNativeFileDescriptorWithoutNdk(env, javaFd);
    }
}

static void network_stack_utils_addArpEntry(JNIEnv *env, jobject thiz, jbyteArray ethAddr,
        jbyteArray ipv4Addr, jstring ifname, jobject javaFd) {
    arpreq req = {};
@@ -84,7 +144,7 @@ static void network_stack_utils_addArpEntry(JNIEnv *env, jobject thiz, jbyteArra
    env->GetStringUTFRegion(ifname, 0, ifLen, req.arp_dev);

    req.arp_flags = ATF_COM;  // Completed entry (ha valid)
    int fd = jniGetFDFromFileDescriptor(env, javaFd);
    int fd = getNativeFileDescriptor(env, javaFd);
    if (fd < 0) {
        jniThrowExceptionFmt(env, "java/io/IOException", "Invalid file descriptor");
        return;
@@ -122,7 +182,7 @@ static void network_stack_utils_attachDhcpFilter(JNIEnv *env, jobject clazz, job
        filter_code,
    };

    int fd = jniGetFDFromFileDescriptor(env, javaFd);
    int fd = getNativeFileDescriptor(env, javaFd);
    if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
        jniThrowExceptionFmt(env, "java/net/SocketException",
                "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
@@ -155,7 +215,7 @@ static void network_stack_utils_attachRaFilter(JNIEnv *env, jobject clazz, jobje
        filter_code,
    };

    int fd = jniGetFDFromFileDescriptor(env, javaFd);
    int fd = getNativeFileDescriptor(env, javaFd);
    if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
        jniThrowExceptionFmt(env, "java/net/SocketException",
                "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
@@ -230,7 +290,7 @@ static void network_stack_utils_attachControlPacketFilter(
        filter_code,
    };

    int fd = jniGetFDFromFileDescriptor(env, javaFd);
    int fd = getNativeFileDescriptor(env, javaFd);
    if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
        jniThrowExceptionFmt(env, "java/net/SocketException",
                "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));