Add FileDescriptor NDK methods

Adds proposed NDK interface for native methods for j.i.FileDescriptor.

Bug: 74469015
Bug: 151443957
Test: atest CtsLibnativehelperTestCases
Change-Id: Ic3ed13df262c3450f7723737050395e30403c1da
diff --git a/Android.bp b/Android.bp
index 3225b1b..4dc70c8 100644
--- a/Android.bp
+++ b/Android.bp
@@ -110,13 +110,15 @@
         "include_platform_header_only",
     ],
     stl: "none",
-    // The ART module is anticipated in 31(S).
-    min_sdk_version: "31",
     stubs: {
         symbol_file: "libnativehelper.map.txt",
-        versions: ["30"],
+        versions: ["31"],
     },
     target: {
+        android: {
+            // FileDescriptor NDK API is Android-only.
+            srcs: ["file_descriptor_jni.c"],
+        },
         windows: {
             enabled: true,
         },
@@ -182,6 +184,20 @@
     license: "NOTICE",
 }
 
+ndk_headers {
+    name: "libnativehelper_ndk_headers",
+    from: "include",
+    to: "",
+    srcs: ["include/android/*.h"],
+    license: "NOTICE",
+}
+
+ndk_library {
+    name: "libnativehelper",
+    symbol_file: "libnativehelper.map.txt",
+    first_version: "31",
+}
+
 //
 // Tests.
 //
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 0e3a29f..018b6b5 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -5,6 +5,9 @@
     },
     {
       "name": "MtsLibnativehelperTestCases"
+    },
+    {
+      "name": "CtsLibnativehelperTestCases"
     }
   ]
 }
diff --git a/file_descriptor_jni.c b/file_descriptor_jni.c
new file mode 100644
index 0000000..7218a18
--- /dev/null
+++ b/file_descriptor_jni.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2020 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 <android/file_descriptor_jni.h>
+
+#include <stddef.h>
+
+#define LOG_TAG "file_descriptor_jni"
+#include "ALog-priv.h"
+
+#include "JniConstants.h"
+
+static void EnsureArgumentIsFileDescriptor(JNIEnv* env, jobject instance) {
+    ALOG_ALWAYS_FATAL_IF(instance == NULL, "FileDescriptor is NULL");
+    jclass jifd = JniConstants_FileDescriptorClass(env);
+    ALOG_ALWAYS_FATAL_IF(!(*env)->IsInstanceOf(env, instance, jifd),
+                         "Argument is not a FileDescriptor");
+}
+
+JNIEXPORT _Nullable jobject AFileDescriptor_create(JNIEnv* env) {
+    return (*env)->NewObject(env,
+                             JniConstants_FileDescriptorClass(env),
+                             JniConstants_FileDescriptor_init(env));
+}
+
+JNIEXPORT int AFileDescriptor_getFD(JNIEnv* env, jobject fileDescriptor) {
+    EnsureArgumentIsFileDescriptor(env, fileDescriptor);
+    return (*env)->GetIntField(env, fileDescriptor, JniConstants_FileDescriptor_descriptor(env));
+}
+
+JNIEXPORT void AFileDescriptor_setFD(JNIEnv* env, jobject fileDescriptor, int fd) {
+    EnsureArgumentIsFileDescriptor(env, fileDescriptor);
+    (*env)->SetIntField(env, fileDescriptor, JniConstants_FileDescriptor_descriptor(env), fd);
+}
diff --git a/include/android/file_descriptor_jni.h b/include/android/file_descriptor_jni.h
new file mode 100644
index 0000000..a375be1
--- /dev/null
+++ b/include/android/file_descriptor_jni.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+/**
+ * @addtogroup FileDescriptor File Descriptor
+ * @{
+ */
+
+/**
+ * @file file_descriptor_jni.h
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+
+#include <jni.h>
+
+__BEGIN_DECLS
+
+#if __ANDROID_API__ >= __ANDROID_API_S__
+
+/**
+ * Returns a new java.io.FileDescriptor.
+ *
+ * The FileDescriptor created represents an invalid Unix file descriptor (represented by
+ * a file descriptor value of -1).
+ *
+ * Callers of this method should be aware that it can fail, returning NULL with a pending Java
+ * exception.
+ *
+ * Available since API level 31.
+ *
+ * \param env a pointer to the JNI Native Interface of the current thread.
+ * \return a java.io.FileDescriptor on success, nullptr if insufficient heap memory is available.
+ */
+jobject AFileDescriptor_create(JNIEnv* env) __INTRODUCED_IN(31);
+
+/**
+ * Returns the Unix file descriptor represented by the given java.io.FileDescriptor.
+ *
+ * A return value of -1 indicates that \a fileDescriptor represents an invalid file descriptor.
+ *
+ * Aborts the program if \a fileDescriptor is not a java.io.FileDescriptor instance.
+ *
+ * Available since API level 31.
+ *
+ * \param env a pointer to the JNI Native Interface of the current thread.
+ * \param fileDescriptor a java.io.FileDescriptor instance.
+ * \return the Unix file descriptor wrapped by \a fileDescriptor.
+ */
+int AFileDescriptor_getFD(JNIEnv* env, jobject fileDescriptor) __INTRODUCED_IN(31);
+
+/**
+ * Sets the Unix file descriptor represented by the given java.io.FileDescriptor.
+ *
+ * This function performs no validation of the Unix file descriptor argument, \a fd. Android uses
+ * the value -1 to represent an invalid file descriptor, all other values are considered valid.
+ * The validity of a file descriptor can be checked with FileDescriptor#valid().
+ *
+ * Aborts the program if \a fileDescriptor is not a java.io.FileDescriptor instance.
+ *
+ * Available since API level 31.
+ *
+ * \param env a pointer to the JNI Native Interface of the current thread.
+ * \param fileDescriptor a java.io.FileDescriptor instance.
+ * \param fd a Unix file descriptor that \a fileDescriptor will subsequently represent.
+ */
+void AFileDescriptor_setFD(JNIEnv* env, jobject fileDescriptor, int fd) __INTRODUCED_IN(31);
+
+#endif  // __ANDROID_API__ >= 31
+
+__END_DECLS
+
+/** @} */
diff --git a/libnativehelper.map.txt b/libnativehelper.map.txt
index 822edad..d1f5911 100644
--- a/libnativehelper.map.txt
+++ b/libnativehelper.map.txt
@@ -1,7 +1,7 @@
 # This library should only export C linkage definitions.
 #
 # VERSION string that follows is derived from <library_name>_<version>.
-LIBNATIVEHELPER_30 {
+LIBNATIVEHELPER_31 {
   global:
     JNI_GetDefaultJavaVMInitArgs;
     JNI_CreateJavaVM;
@@ -34,3 +34,13 @@
   local:
     *;
 };
+
+# NDK API for libnativehelper.
+LIBNATIVEHELPER_S { # introduced=31
+  global:
+    AFileDescriptor_create;
+    AFileDescriptor_getFD;
+    AFileDescriptor_setFD;
+  local:
+    *;
+};