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

Commit 7f380d39 authored by Remi NGUYEN VAN's avatar Remi NGUYEN VAN Committed by Automerger Merge Worker
Browse files

Merge "Remove dependency on legacy jniGetFDFromFileDescriptor" am: 7f03c094

Original change: https://android-review.googlesource.com/c/platform/packages/modules/NetworkStack/+/1413498

Change-Id: I8f37dd380f9357ebcddc7e7987acd3653e07d862
parents 95cd1ff4 7f03c094
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));