libnativehelper API split

Split JNIHelp.h into JNIHelp.h and JNIPlatformHelp.h. The former
contains methods that depend on public Java API. The latter contains
methods primarily intended for platform that depend on non-public Java
API fields and methods, e.g j.l.FileDescriptor.

Place JNIPlatformHelp.h and JniInvocation.h under include_platform/.

Remove API covered by JNIPlatform.h from
libnativehelper_compat_libc++. Any code that requires these methods
should use libnativehelper instead.

Rename platform_include/ to include_platform_header_only/.

Bug: 151443957
Test: atest CtsLibnativehelperTestCases
Test: Treehugger
Change-Id: If2f563ea5c82882d3a77a7b9af7c508bfa8acc6e
Merged-In: If2f563ea5c82882d3a77a7b9af7c508bfa8acc6e
Exempt-From-Owner-Approval: cherry pick
(cherry picked from commit e77eceff3521ff44382afc0540924247a57fa908)
diff --git a/Android.bp b/Android.bp
index 37ab0ff..1f13e27 100644
--- a/Android.bp
+++ b/Android.bp
@@ -35,7 +35,7 @@
         "//apex_available:platform",
         "//apex_available:anyapex",
     ],
-    // recovery_available currently required for libchome (https://r.android.com/799940).
+    // recovery_available currently required for libchrome (https://r.android.com/799940).
     recovery_available: true,
     visibility: ["//visibility:public"],
     stl: "none",
@@ -59,10 +59,9 @@
             enabled: true,
         },
     },
-    sdk_version: "current",
     // As part of mainline modules(APEX), it should support at least 29(Q)
     min_sdk_version: "29",
-
+    sdk_version: "minimum",
     apex_available: [
         "//apex_available:platform",
         "//apex_available:anyapex",
@@ -73,16 +72,16 @@
     name: "jni_platform_headers",
     host_supported: true,
     export_include_dirs: [
-        "platform_include",
+        "include_platform_header_only",
     ],
     header_libs: ["jni_headers"],
     export_header_lib_headers: ["jni_headers"],
+    sdk_version: "minimum",
     target: {
         windows: {
             enabled: true,
         },
     },
-
     apex_available: [
         "//apex_available:platform",
         "com.android.art.debug",
@@ -98,6 +97,7 @@
         "DlHelp.c",
         "ExpandableString.c",
         "JNIHelp.c",
+        "JNIPlatformHelp.c",
         "JniConstants.c",
         "JniInvocation.c",
     ],
@@ -105,20 +105,23 @@
     export_include_dirs: [
         "header_only_include",
         "include",
-        "platform_include",
+        "include_jni",
+        "include_platform",
+        "include_platform_header_only",
     ],
-    header_libs: ["jni_headers"],
-    export_header_lib_headers: ["jni_headers"],
     stl: "none",
+    // The ART module is anticipated in 31(S).
+    min_sdk_version: "31",
     stubs: {
         symbol_file: "libnativehelper.map.txt",
-        versions: ["1"],
+        versions: ["30"],
     },
     target: {
         windows: {
             enabled: true,
         },
     },
+    // Only distributed in the ART Module.
     apex_available: [
         "com.android.art.release",
         "com.android.art.debug",
@@ -143,13 +146,14 @@
     ],
     local_include_dirs: [
         "header_only_include",
-        "platform_include",
+        "include_platform_header_only",
     ],
     srcs: [
-        "DlHelp.c",
         "ExpandableString.c",
         "JNIHelp.c",
-        "JniConstants.c",
+        // This is needed for NetworkStack and Tethering until a better
+        // solution is found (b/158749603).
+        "JNIHelpCompat.c",
     ],
     shared_libs: [
         "liblog",
diff --git a/JNIHelp.c b/JNIHelp.c
index 36df7f9..fdc309e 100644
--- a/JNIHelp.c
+++ b/JNIHelp.c
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <nativehelper/libnativehelper_api.h>
+#include "include/nativehelper/JNIHelp.h"
 
 #include <stdbool.h>
 #include <stdio.h>
@@ -27,7 +27,6 @@
 #include "ALog-priv.h"
 
 #include "ExpandableString.h"
-#include "JniConstants.h"
 
 //
 // Helper methods
@@ -50,16 +49,16 @@
 #endif
 }
 
-static int GetBufferPosition(JNIEnv* env, jobject nioBuffer) {
-    return(*env)->GetIntField(env, nioBuffer, JniConstants_NioBuffer_position(env));
-}
-
-static int GetBufferLimit(JNIEnv* env, jobject nioBuffer) {
-    return(*env)->GetIntField(env, nioBuffer, JniConstants_NioBuffer_limit(env));
-}
-
-static int GetBufferElementSizeShift(JNIEnv* env, jobject nioBuffer) {
-    return(*env)->GetIntField(env, nioBuffer, JniConstants_NioBuffer__elementSizeShift(env));
+static jmethodID FindMethod(JNIEnv* env,
+                            const char* className,
+                            const char* methodName,
+                            const char* descriptor) {
+    // This method is only valid for classes in the core library which are
+    // not unloaded during the lifetime of managed code execution.
+    jclass clazz = (*env)->FindClass(env, className);
+    jmethodID methodId = (*env)->GetMethodID(env, clazz, methodName, descriptor);
+    (*env)->DeleteLocalRef(env, clazz);
+    return methodId;
 }
 
 static bool AppendJString(JNIEnv* env, jstring text, struct ExpandableString* dst) {
@@ -79,10 +78,9 @@
  */
 static bool GetExceptionSummary(JNIEnv* env, jthrowable thrown, struct ExpandableString* dst) {
     // Summary is <exception_class_name> ": " <exception_message>
-    jclass exceptionClass = (*env)->GetObjectClass(env, thrown);        // always succeeds
-
-    jstring className =
-        (jstring) (*env)->CallObjectMethod(env, exceptionClass, JniConstants_Class_getName(env));
+    jclass exceptionClass = (*env)->GetObjectClass(env, thrown);  // Always succeeds
+    jmethodID getName = FindMethod(env, "java/lang/Class", "getName", "()Ljava/lang/String;");
+    jstring className = (jstring) (*env)->CallObjectMethod(env, exceptionClass, getName);
     if (className == NULL) {
         ExpandableStringAssign(dst, "<error getting class name>");
         (*env)->ExceptionClear(env);
@@ -101,8 +99,9 @@
     (*env)->DeleteLocalRef(env, className);
     className = NULL;
 
-    jstring message =
-        (jstring) (*env)->CallObjectMethod(env, thrown, JniConstants_Throwable_getMessage(env));
+    jmethodID getMessage =
+        FindMethod(env, "java/lang/Throwable", "getMessage", "()Ljava/lang/String;");
+    jstring message = (jstring) (*env)->CallObjectMethod(env, thrown, getMessage);
     if (message == NULL) {
         return true;
     }
@@ -134,11 +133,9 @@
 }
 
 static jstring StringWriterToString(JNIEnv* env, jobject stringWriter) {
-    jclass clazz = (*env)->FindClass(env, "java/io/StringWriter");
-    jmethodID toString = (*env)->GetMethodID(env, clazz, "toString", "()Ljava/lang/String;");
-    jobject result = (*env)->CallObjectMethod(env, stringWriter, toString);
-    (*env)->DeleteLocalRef(env, clazz);
-    return (jstring) result;
+    jmethodID toString =
+        FindMethod(env, "java/io/StringWriter", "toString", "()Ljava/lang/String;");
+    return (jstring) (*env)->CallObjectMethod(env, stringWriter, toString);
 }
 
 static jobject NewPrintWriter(JNIEnv* env, jobject writer) {
@@ -167,7 +164,10 @@
         return false;
     }
 
-    (*env)->CallVoidMethod(env, thrown, JniConstants_Throwable_printStackTrace(env), pw);
+    jmethodID printStackTrace =
+        FindMethod(env, "java/lang/Throwable", "printStackTrace", "(Ljava/io/PrintWriter;)V");
+    (*env)->CallVoidMethod(env, thrown, printStackTrace, pw);
+
     jstring trace = StringWriterToString(env, sw);
 
     (*env)->DeleteLocalRef(env, pw);
@@ -234,7 +234,7 @@
 }
 
 //
-// libnativehelper API
+// JNIHelp external API
 //
 
 int jniRegisterNativeMethods(JNIEnv* env, const char* className,
@@ -317,70 +317,9 @@
     return jniThrowException(env, "java/io/IOException", message);
 }
 
-jobject jniCreateFileDescriptor(JNIEnv* env, int fd) {
-    jobject fileDescriptor = (*env)->NewObject(env,
-                                               JniConstants_FileDescriptorClass(env),
-                                               JniConstants_FileDescriptor_init(env));
-    // NOTE: NewObject ensures that an OutOfMemoryError will be seen by the Java
-    // caller if the alloc fails, so we just return nullptr when that happens.
-    if (fileDescriptor != NULL)  {
-        jniSetFileDescriptorOfFD(env, fileDescriptor, fd);
-    }
-    return fileDescriptor;
-}
-
-int jniGetFDFromFileDescriptor(JNIEnv* env, jobject fileDescriptor) {
-    if (fileDescriptor != NULL) {
-        return (*env)->GetIntField(env, fileDescriptor,
-                                   JniConstants_FileDescriptor_descriptor(env));
-    } else {
-        return -1;
-    }
-}
-
-void jniSetFileDescriptorOfFD(JNIEnv* env, jobject fileDescriptor, int value) {
-    if (fileDescriptor == NULL) {
-        jniThrowNullPointerException(env, "null FileDescriptor");
-    } else {
-        (*env)->SetIntField(env,
-                            fileDescriptor, JniConstants_FileDescriptor_descriptor(env), value);
-    }
-}
-
-jarray jniGetNioBufferBaseArray(JNIEnv* env, jobject nioBuffer) {
-    jclass nioAccessClass = JniConstants_NIOAccessClass(env);
-    jmethodID getBaseArrayMethod = JniConstants_NIOAccess_getBaseArray(env);
-    jobject object = (*env)->CallStaticObjectMethod(env,
-                                                    nioAccessClass, getBaseArrayMethod, nioBuffer);
-    return (jarray) object;
-}
-
-int jniGetNioBufferBaseArrayOffset(JNIEnv* env, jobject nioBuffer) {
-    jclass nioAccessClass = JniConstants_NIOAccessClass(env);
-    jmethodID getBaseArrayOffsetMethod = JniConstants_NIOAccess_getBaseArrayOffset(env);
-    return (*env)->CallStaticIntMethod(env, nioAccessClass, getBaseArrayOffsetMethod, nioBuffer);
-}
-
-jlong jniGetNioBufferPointer(JNIEnv* env, jobject nioBuffer) {
-    jlong baseAddress = (*env)->GetLongField(env, nioBuffer, JniConstants_NioBuffer_address(env));
-    if (baseAddress != 0) {
-        const int position = GetBufferPosition(env, nioBuffer);
-        const int shift = GetBufferElementSizeShift(env, nioBuffer);
-        baseAddress += position << shift;
-    }
-    return baseAddress;
-}
-
-jlong jniGetNioBufferFields(JNIEnv* env, jobject nioBuffer,
-                            jint* position, jint* limit, jint* elementSizeShift) {
-    *position = GetBufferPosition(env, nioBuffer);
-    *limit = GetBufferLimit(env, nioBuffer);
-    *elementSizeShift = GetBufferElementSizeShift(env, nioBuffer);
-    return (*env)->GetLongField(env, nioBuffer, JniConstants_NioBuffer_address(env));
-}
-
 jobject jniGetReferent(JNIEnv* env, jobject ref) {
-    return (*env)->CallObjectMethod(env, ref, JniConstants_Reference_get(env));
+    jmethodID get = FindMethod(env, "java/lang/ref/Reference", "get", "()Ljava/lang/Object;");
+    return (*env)->CallObjectMethod(env, ref, get);
 }
 
 jstring jniCreateString(JNIEnv* env, const jchar* unicodeChars, jsize len) {
@@ -388,5 +327,8 @@
 }
 
 jobjectArray jniCreateStringArray(C_JNIEnv* env, size_t count) {
-    return (*env)->NewObjectArray(env, count, JniConstants_StringClass(env), NULL);
+    jclass stringClass = (*env)->FindClass(env,  "java/lang/String");
+    jobjectArray result = (*env)->NewObjectArray(env, count, stringClass, NULL);
+    (*env)->DeleteLocalRef(env, stringClass);
+    return result;
 }
diff --git a/JNIHelpCompat.c b/JNIHelpCompat.c
new file mode 100644
index 0000000..e120cb0
--- /dev/null
+++ b/JNIHelpCompat.c
@@ -0,0 +1,50 @@
+/*
+ * 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 "include_platform/nativehelper/JNIPlatformHelp.h"
+
+#include <dlfcn.h>
+#include "include_jni/jni.h"
+#include <stdbool.h>
+#include <stddef.h>
+
+#define LOG_TAG "JNIHelpCompat"
+#include "ALog-priv.h"
+
+/*
+ * This is compatibility code so the NetworkStack.apk and Tethering mainline module continues to
+ * work on Q and R. This code should not be used anywhere else. When this module is no longer
+ * required to run on Q and R, this compat code should be removed. Ideally we find a solution
+ * in NetworkStack and Tethering instead of here (b/158749603).
+ */
+int jniGetFDFromFileDescriptor_QR(JNIEnv* env, jobject fileDescriptor) {
+    if (fileDescriptor == NULL) {
+        return -1;
+    }
+
+    static jfieldID g_descriptorFieldID = NULL;
+    if (g_descriptorFieldID == NULL) {
+        jclass fileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor");
+        g_descriptorFieldID = (*env)->GetFieldID(env, fileDescriptorClass, "descriptor", "I");
+        (*env)->DeleteLocalRef(env, fileDescriptorClass);
+    }
+
+    return (*env)->GetIntField(env, fileDescriptor, g_descriptorFieldID);
+}
+
+jint jniGetFDFromFileDescriptor(JNIEnv* env, jobject fileDescriptor) {
+    return jniGetFDFromFileDescriptor_QR(env, fileDescriptor);
+}
diff --git a/JNIPlatformHelp.c b/JNIPlatformHelp.c
new file mode 100644
index 0000000..d80b048
--- /dev/null
+++ b/JNIPlatformHelp.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2006 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_platform/nativehelper/JNIPlatformHelp.h"
+
+#include <stddef.h>
+
+#include "JniConstants.h"
+
+static int GetBufferPosition(JNIEnv* env, jobject nioBuffer) {
+    return(*env)->GetIntField(env, nioBuffer, JniConstants_NioBuffer_position(env));
+}
+
+static int GetBufferLimit(JNIEnv* env, jobject nioBuffer) {
+    return(*env)->GetIntField(env, nioBuffer, JniConstants_NioBuffer_limit(env));
+}
+
+static int GetBufferElementSizeShift(JNIEnv* env, jobject nioBuffer) {
+    return(*env)->GetIntField(env, nioBuffer, JniConstants_NioBuffer__elementSizeShift(env));
+}
+
+jobject jniCreateFileDescriptor(JNIEnv* env, int fd) {
+    jobject fileDescriptor = (*env)->NewObject(env,
+                                               JniConstants_FileDescriptorClass(env),
+                                               JniConstants_FileDescriptor_init(env));
+    // NOTE: NewObject ensures that an OutOfMemoryError will be seen by the Java
+    // caller if the alloc fails, so we just return nullptr when that happens.
+    if (fileDescriptor != NULL)  {
+        jniSetFileDescriptorOfFD(env, fileDescriptor, fd);
+    }
+    return fileDescriptor;
+}
+
+int jniGetFDFromFileDescriptor(JNIEnv* env, jobject fileDescriptor) {
+    if (fileDescriptor != NULL) {
+        return (*env)->GetIntField(env, fileDescriptor,
+                                   JniConstants_FileDescriptor_descriptor(env));
+    } else {
+        return -1;
+    }
+}
+
+void jniSetFileDescriptorOfFD(JNIEnv* env, jobject fileDescriptor, int value) {
+    if (fileDescriptor == NULL) {
+        jniThrowNullPointerException(env, "null FileDescriptor");
+    } else {
+        (*env)->SetIntField(env,
+                            fileDescriptor, JniConstants_FileDescriptor_descriptor(env), value);
+    }
+}
+
+jarray jniGetNioBufferBaseArray(JNIEnv* env, jobject nioBuffer) {
+    jclass nioAccessClass = JniConstants_NIOAccessClass(env);
+    jmethodID getBaseArrayMethod = JniConstants_NIOAccess_getBaseArray(env);
+    jobject object = (*env)->CallStaticObjectMethod(env,
+                                                    nioAccessClass, getBaseArrayMethod, nioBuffer);
+    return (jarray) object;
+}
+
+int jniGetNioBufferBaseArrayOffset(JNIEnv* env, jobject nioBuffer) {
+    jclass nioAccessClass = JniConstants_NIOAccessClass(env);
+    jmethodID getBaseArrayOffsetMethod = JniConstants_NIOAccess_getBaseArrayOffset(env);
+    return (*env)->CallStaticIntMethod(env, nioAccessClass, getBaseArrayOffsetMethod, nioBuffer);
+}
+
+jlong jniGetNioBufferPointer(JNIEnv* env, jobject nioBuffer) {
+    jlong baseAddress = (*env)->GetLongField(env, nioBuffer, JniConstants_NioBuffer_address(env));
+    if (baseAddress != 0) {
+        const int position = GetBufferPosition(env, nioBuffer);
+        const int shift = GetBufferElementSizeShift(env, nioBuffer);
+        baseAddress += position << shift;
+    }
+    return baseAddress;
+}
+
+jlong jniGetNioBufferFields(JNIEnv* env, jobject nioBuffer,
+                            jint* position, jint* limit, jint* elementSizeShift) {
+    *position = GetBufferPosition(env, nioBuffer);
+    *limit = GetBufferLimit(env, nioBuffer);
+    *elementSizeShift = GetBufferElementSizeShift(env, nioBuffer);
+    return (*env)->GetLongField(env, nioBuffer, JniConstants_NioBuffer_address(env));
+}
diff --git a/JniConstants.c b/JniConstants.c
index 08660e0..177298e 100644
--- a/JniConstants.c
+++ b/JniConstants.c
@@ -21,8 +21,6 @@
 #include <stddef.h>
 #include <string.h>
 
-#include <nativehelper/libnativehelper_api.h>
-
 #define LOG_TAG "JniConstants"
 #include "ALog-priv.h"
 
@@ -30,26 +28,18 @@
 //   <class, signature, androidOnly>
 
 #define JCLASS_CONSTANTS_LIST(V)                                            \
-  V(Class, "java/lang/Class", false)                                        \
   V(FileDescriptor, "java/io/FileDescriptor", false)                        \
   V(NIOAccess, "java/nio/NIOAccess", true)                                  \
-  V(NioBuffer, "java/nio/Buffer", false)                                    \
-  V(Reference, "java/lang/ref/Reference", false)                            \
-  V(String, "java/lang/String", false)                                      \
-  V(Throwable, "java/lang/Throwable", false)
+  V(NioBuffer, "java/nio/Buffer", false)
 
 // jmethodID's of public methods constants list:
 //   <Class, method, method-string, signature, is_static>
 #define JMETHODID_CONSTANTS_LIST(V)                                                         \
-  V(Class, getName, "getName", "()Ljava/lang/String;", false)                               \
   V(FileDescriptor, init, "<init>", "()V", false)                                           \
   V(NIOAccess, getBaseArray, "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;", true) \
   V(NIOAccess, getBaseArrayOffset, "getBaseArrayOffset", "(Ljava/nio/Buffer;)I", true)      \
   V(NioBuffer, array, "array", "()Ljava/lang/Object;", false)                               \
-  V(NioBuffer, arrayOffset, "arrayOffset", "()I", false)                                    \
-  V(Reference, get, "get", "()Ljava/lang/Object;", false)                                   \
-  V(Throwable, getMessage, "getMessage", "()Ljava/lang/String;", false)                     \
-  V(Throwable, printStackTrace, "printStackTrace", "(Ljava/io/PrintWriter;)V", false)
+  V(NioBuffer, arrayOffset, "arrayOffset", "()I", false)
 
 // jfieldID constants list:
 //   <Class, field, signature, is_static>
diff --git a/JniConstants.h b/JniConstants.h
index aa66e25..cb8992d 100644
--- a/JniConstants.h
+++ b/JniConstants.h
@@ -18,25 +18,19 @@
 
 #include <sys/cdefs.h>
 
-#include "include_jni/jni.h"
+#include <jni.h>
 
 __BEGIN_DECLS
 
-
 //
 // Classes in constants cache.
 //
 // NB The implementations of these methods are generated by the JCLASS_ACCESSOR_IMPL macro in
 // JniConstants.c.
 //
-jclass JniConstants_ClassClass(JNIEnv* env);
 jclass JniConstants_FileDescriptorClass(JNIEnv* env);
 jclass JniConstants_NIOAccessClass(JNIEnv* env);
 jclass JniConstants_NioBufferClass(JNIEnv* env);
-jclass JniConstants_ReferenceClass(JNIEnv* env);
-jclass JniConstants_StringClass(JNIEnv* env);
-jclass JniConstants_ThrowableClass(JNIEnv* env);
-
 
 //
 // Methods in the constants cache.
@@ -45,14 +39,10 @@
 // JniConstants.c.
 //
 jmethodID JniConstants_FileDescriptor_init(JNIEnv* env);
-jmethodID JniConstants_Class_getName();
 jmethodID JniConstants_NIOAccess_getBaseArray(JNIEnv* env);
 jmethodID JniConstants_NIOAccess_getBaseArrayOffset(JNIEnv* env);
 jmethodID JniConstants_NioBuffer_array(JNIEnv* env);
 jmethodID JniConstants_NioBuffer_arrayOffset(JNIEnv* env);
-jmethodID JniConstants_Reference_get(JNIEnv* env);
-jmethodID JniConstants_Throwable_getMessage(JNIEnv* env);
-jmethodID JniConstants_Throwable_printStackTrace(JNIEnv* env);
 
 //
 // Fields in the constants cache.
diff --git a/JniInvocation.c b/JniInvocation.c
index 2099a28..bace941 100644
--- a/JniInvocation.c
+++ b/JniInvocation.c
@@ -14,17 +14,16 @@
  * limitations under the License.
  */
 
-#include "nativehelper/libnativehelper_api.h"
-
-#include "jni.h"
+#include "include_platform/nativehelper/JniInvocation.h"
 
 #define LOG_TAG "JniInvocation"
-#include <log/log.h>
+#include "ALog-priv.h"
 
 #if defined(__ANDROID__)
 #include <sys/system_properties.h>
 #endif
 
+#include <jni.h>
 #include <stdbool.h>
 #include <string.h>
 
diff --git a/README b/README
deleted file mode 100644
index 5a5f5d4..0000000
--- a/README
+++ /dev/null
@@ -1,11 +0,0 @@
-Support functions for Android's class libraries
-
-
-These are VM-agnostic native functions that implement methods for system
-class libraries.  All code here:
-
- - MUST not be associated with an android.* class (that code lives in
-   frameworks/base/).
- - SHOULD be written in C rather than C++ where possible.
-
-Some helper functions are defined in include/nativehelper/JNIHelp.h.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..ea96f65
--- /dev/null
+++ b/README.md
@@ -0,0 +1,97 @@
+# libnativehelper
+
+libnativehelper is a collection of JNI related utilities used in Android.
+
+There are several header and binary libraries here and not all of the
+functionality fits together well. The header libraries are mostly C++
+based. The binary libraries are entirely written in C with no C++
+dependencies. This is by design as the code here can be distributed in
+multiple ways, including mainline modules, so keeping the size down
+benefits everyone with smaller downloads and a stable ABI.
+
+## Header Libraries
+
+### jni_headers
+
+This is a header library that contains provides the API represented in
+the JNI Specification 1.6. Any project in Android that depends on
+`jni.h` should depend on this.
+
+See:
+
+* [jni.h](include_jni/jni.h)
+
+### libnativehelper_header_only
+
+These headers provide utilities that defined entirely within the
+headers. There are scoped resource classes that make common JNI
+patterns of acquiring and releasing resources safer to use than the
+JNI specification equivalents. Examples being `ScopedLocalRef` to
+manage the lifetime of local references and `ScopedUtfChars` to manage
+the lifetime of Java strings in native code and provide access to utf8
+characters.
+
+See:
+
+* [nativehelper/nativehelper_utils.h](header_only_include/nativehelper/nativehelper_utils.h)
+* [nativehelper/scoped_utf_chars.h](header_only_include/nativehelper/scoped_utf_chars.h)
+* [nativehelper/scoped_bytes.h](header_only_include/nativehelper/scoped_bytes.h)
+* [nativehelper/scoped_string_chars.h](header_only_include/nativehelper/scoped_string_chars.h)
+* [nativehelper/scoped_primitive_array.h](header_only_include/nativehelper/scoped_primitive_array.h)
+* [nativehelper/scoped_local_ref.h](header_only_include/nativehelper/scoped_local_ref.h)
+* [nativehelper/scoped_local_frame.h](header_only_include/nativehelper/scoped_local_frame.h)
+
+### jni_platform_headers
+
+The `jni_macros.h` header provide compile time checking of JNI methods
+implemented in C++. They ensure the C++ method declaration match the
+Java signature they are associated with.
+
+See:
+
+* [nativehelper/jni_macros.h](include_platform_header_only/nativehelper/jni_macros.h)
+
+## Libraries
+
+### libnativehelper
+
+A shared library distributed in the ART module that provides helper
+routines built on Java APIs. This library depends on details that are
+private to libcore and use should be restricted to platform code and
+within the ART module.
+
+This library also contains the JNI invocation API from the JNI
+Specification and the glue that connects the ART runtime to the API
+implementation. The glue logic is platform only as it is used with the
+Zygote and the standalone dalvikvm.
+
+See:
+* [nativehelper/JNIHelp.h](include/nativehelper/JNIHelp.h)
+* [nativehelper/JniInvocation.h](include_platform/nativehelper/JniInvocation.h)
+* [nativehelper/JNIPlatformHelp.h](include_platform/nativehelper/JNIPlatformHelp.h)
+* [nativehelper/ScopedBytes.h](include/nativehelper/ScopedBytes.h)
+* [nativehelper/ScopedUtfChars.h](include/nativehelper/ScopedUtfChars.h)
+* [nativehelper/ScopedLocalFrame.h](include/nativehelper/ScopedLocalFrame.h)
+* [nativehelper/ScopedLocalRef.h](include/nativehelper/ScopedLocalRef.h)
+* [nativehelper/ScopedPrimitiveArray.h](include/nativehelper/ScopedPrimitiveArray.h)
+* [nativehelper/ScopedStringChars.h](include/nativehelper/ScopedStringChars.h)
+* [nativehelper/toStringArray.h](include/nativehelper/toStringArray.h)
+
+### libnativehelper_compat_libc++
+
+This shared and static library contains a subset of the helper
+routines in libnativehelper based on public Java API. This code can be
+statically linked as the Java APIs it depends on are considered
+stable. The name of this library is a misnomer since it contains no
+C++ code.
+
+See:
+
+* [nativehelper/JNIHelp.h](include/nativehelper/JNIHelp.h)
+* [nativehelper/ScopedBytes.h](include/nativehelper/ScopedBytes.h)
+* [nativehelper/ScopedUtfChars.h](include/nativehelper/ScopedUtfChars.h)
+* [nativehelper/ScopedLocalFrame.h](include/nativehelper/ScopedLocalFrame.h)
+* [nativehelper/ScopedLocalRef.h](include/nativehelper/ScopedLocalRef.h)
+* [nativehelper/ScopedPrimitiveArray.h](include/nativehelper/ScopedPrimitiveArray.h)
+* [nativehelper/ScopedStringChars.h](include/nativehelper/ScopedStringChars.h)
+* [nativehelper/toStringArray.h](include/nativehelper/toStringArray.h)
diff --git a/include/nativehelper/JNIHelp.h b/include/nativehelper/JNIHelp.h
index e6e3c47..ad6eb25 100644
--- a/include/nativehelper/JNIHelp.h
+++ b/include/nativehelper/JNIHelp.h
@@ -22,15 +22,104 @@
  */
 #pragma once
 
+#include <sys/cdefs.h>
+
 #include <errno.h>
 #include <unistd.h>
 
-#include "libnativehelper_api.h"
+#include <jni.h>
 
 #ifndef NELEM
 #define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
 #endif
 
+__BEGIN_DECLS
+
+
+/*
+ * Register one or more native methods with a particular class.  "className" looks like
+ * "java/lang/String". Aborts on failure, returns 0 on success.
+ */
+int jniRegisterNativeMethods(C_JNIEnv* env,
+                             const char* className,
+                             const JNINativeMethod* gMethods,
+                             int numMethods);
+
+/*
+ * Throw an exception with the specified class and an optional message.
+ *
+ * The "className" argument will be passed directly to FindClass, which
+ * takes strings with slashes (e.g. "java/lang/Object").
+ *
+ * If an exception is currently pending, we log a warning message and
+ * clear it.
+ *
+ * Returns 0 on success, nonzero if something failed (e.g. the exception
+ * class couldn't be found, so *an* exception will still be pending).
+ *
+ * Currently aborts the VM if it can't throw the exception.
+ */
+int jniThrowException(C_JNIEnv* env, const char* className, const char* msg);
+
+/*
+ * Throw an exception with the specified class and formatted error message.
+ *
+ * The "className" argument will be passed directly to FindClass, which
+ * takes strings with slashes (e.g. "java/lang/Object").
+ *
+ * If an exception is currently pending, we log a warning message and
+ * clear it.
+ *
+ * Returns 0 on success, nonzero if something failed (e.g. the exception
+ * class couldn't be found, so *an* exception will still be pending).
+ *
+ * Currently aborts the VM if it can't throw the exception.
+ */
+int jniThrowExceptionFmt(C_JNIEnv* env, const char* className, const char* fmt, va_list args);
+
+/*
+ * Throw a java.lang.NullPointerException, with an optional message.
+ */
+int jniThrowNullPointerException(C_JNIEnv* env, const char* msg);
+
+/*
+ * Throw a java.lang.RuntimeException, with an optional message.
+ */
+int jniThrowRuntimeException(C_JNIEnv* env, const char* msg);
+
+/*
+ * Throw a java.io.IOException, generating the message from errno.
+ */
+int jniThrowIOException(C_JNIEnv* env, int errnum);
+
+/*
+ * Returns the reference from a java.lang.ref.Reference.
+ */
+jobject jniGetReferent(C_JNIEnv* env, jobject ref);
+
+/*
+ * Returns a Java String object created from UTF-16 data either from jchar or,
+ * if called from C++11, char16_t (a bitwise identical distinct type).
+ */
+jstring jniCreateString(C_JNIEnv* env, const jchar* unicodeChars, jsize len);
+
+/*
+ * Allocates a new array for java/lang/String instances with space for |count| elements. Elements
+ * are initially null.
+ *
+ * Returns a new array on success or nullptr in case of failure. This method raises an
+ * OutOfMemoryError exception if allocation fails.
+ */
+jobjectArray jniCreateStringArray(C_JNIEnv* env, size_t count);
+
+/*
+ * Log a message and an exception.
+ * If exception is NULL, logs the current exception in the JNI environment.
+ */
+void jniLogException(C_JNIEnv* env, int priority, const char* tag, jthrowable exception);
+
+__END_DECLS
+
 /*
  * For C++ code, we provide inlines that map to the C functions.  g++ always
  * inlines these, even on non-optimized builds.
@@ -68,36 +157,6 @@
     return jniThrowIOException(&env->functions, errnum);
 }
 
-inline jobject jniCreateFileDescriptor(JNIEnv* env, int fd) {
-    return jniCreateFileDescriptor(&env->functions, fd);
-}
-
-inline int jniGetFDFromFileDescriptor(JNIEnv* env, jobject fileDescriptor) {
-    return jniGetFDFromFileDescriptor(&env->functions, fileDescriptor);
-}
-
-inline void jniSetFileDescriptorOfFD(JNIEnv* env, jobject fileDescriptor, int value) {
-    jniSetFileDescriptorOfFD(&env->functions, fileDescriptor, value);
-}
-
-inline jarray jniGetNioBufferBaseArray(JNIEnv* env, jobject nioBuffer) {
-    return jniGetNioBufferBaseArray(&env->functions, nioBuffer);
-}
-
-inline jint jniGetNioBufferBaseArrayOffset(JNIEnv* env, jobject nioBuffer) {
-    return jniGetNioBufferBaseArrayOffset(&env->functions, nioBuffer);
-}
-
-inline jlong jniGetNioBufferFields(JNIEnv* env, jobject nioBuffer,
-                                   jint* position, jint* limit, jint* elementSizeShift) {
-    return jniGetNioBufferFields(&env->functions, nioBuffer,
-                                 position, limit, elementSizeShift);
-}
-
-inline jlong jniGetNioBufferPointer(JNIEnv* env, jobject nioBuffer) {
-    return jniGetNioBufferPointer(&env->functions, nioBuffer);
-}
-
 inline jobject jniGetReferent(JNIEnv* env, jobject ref) {
     return jniGetReferent(&env->functions, ref);
 }
diff --git a/include/nativehelper/JNIHelpCompat.h b/include/nativehelper/JNIHelpCompat.h
new file mode 100644
index 0000000..39bf43c
--- /dev/null
+++ b/include/nativehelper/JNIHelpCompat.h
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+/*
+ * DO NOT INCLUDE THIS HEADER IN NEW CODE. IT IS FOR LEGACY COMPATIBILITY ONLY.
+ */
+
+#pragma once
+
+#include <jni.h>
+
+__BEGIN_DECLS
+
+/*
+ * Returns the UNIX file descriptor as an integer from a
+ * java.io.FileDescriptor instance or -1 if the java.io.FileDescriptor
+ * is NULL.
+ *
+ * Exported by libnativehelper_compat_libc++.so.
+ *
+ * Note:
+ *
+ * This method exists solely for NetworkStack and Tethering until a better
+ * solution can be found (b/158749603).
+ *
+ * In Android S, libnativehelper_compat_libc++.so had methods depending on
+ * private Java API surfaces removed and those methods are only available in
+ * libnativehelper.so. From Android S, libnativehelper.so is a public
+ * library that is distributed in ART module and so we can ensure the
+ * private API it depends on is compatible with the current Java core
+ * libraries that are also part of the ART module.
+ *
+ * jniGetFDFromFileDescriptor() could not be removed from
+ * libnativehelper_compat_libc++.so because NetworkStack and Tethering need
+ * to be compatible with Android versions Q and R. On these releases,
+ * libnativehelper.so is not available to these modules, ie NetworkStack
+ * ships as an APK, so effectively an app.
+ */
+int jniGetFDFromFileDescriptor(C_JNIEnv* env, jobject fileDescriptor);
+
+/*
+ * Returns the UNIX file descriptor as an integer from a
+ * java.io.FileDescriptor instance or -1 if the java.io.FileDescriptor
+ * is NULL.
+ *
+ * Exported by libnativehelper_compat_libc++.so
+ *
+ * Note:
+ *
+ * This method exists primarily for testing purposes. It is the
+ * implementation used by jniGetFDFromFileDescriptor() exported by
+ * libnativehelper_compat_libc++.so.
+ *
+ * This method exists to make the tested surface area explicit in the
+ * CtsLibnativehelperTestCases and ensure the compatibility version is
+ * tested. The symbol jniGetFDFromFileDescriptor() is exported by both
+ * libnativehelper_compat_libc++.so and libnativehelper.so and the test
+ * harness depends on libnativehelper_compat_libc++.so, but most of the
+ * tests cover libnativehelper.so.
+ */
+int jniGetFDFromFileDescriptor_QR(C_JNIEnv* env, jobject fileDescriptor);
+
+__END_DECLS
+
+/*
+ * For C++ code, we provide inlines that map to the C functions.  g++ always
+ * inlines these, even on non-optimized builds.
+ */
+#if defined(__cplusplus)
+
+inline int jniGetFDFromFileDescriptor(JNIEnv* env, jobject fileDescriptor) {
+    return jniGetFDFromFileDescriptor(&env->functions, fileDescriptor);
+}
+
+inline int jniGetFDFromFileDescriptor_QR(JNIEnv* env, jobject fileDescriptor) {
+    return jniGetFDFromFileDescriptor_QR(&env->functions, fileDescriptor);
+}
+
+#endif  // defined(__cplusplus)
diff --git a/include/nativehelper/JniInvocation.h b/include/nativehelper/JniInvocation.h
deleted file mode 100644
index 7494894..0000000
--- a/include/nativehelper/JniInvocation.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-#pragma once
-
-#include "libnativehelper_api.h"
-
-#ifdef __cplusplus
-
-// JniInvocation adds a layer of indirection for applications using
-// the JNI invocation API to allow the JNI implementation to be
-// selected dynamically. Apps can specify a specific implementation to
-// be used by calling InitJniInvocation. If this is not done, the
-// library will chosen based on the value of Android system property
-// persist.sys.dalvik.vm.lib on the device, and otherwise fall back to
-// a hard-coded default implementation.
-class JniInvocation final {
- public:
-  JniInvocation() {
-    impl_ = JniInvocationCreate();
-  }
-
-  ~JniInvocation() {
-    JniInvocationDestroy(impl_);
-  }
-
-  // Initialize JNI invocation API. library should specifiy a valid
-  // shared library for opening via dlopen providing a JNI invocation
-  // implementation, or null to allow defaulting via
-  // persist.sys.dalvik.vm.lib.
-  bool Init(const char* library) {
-    return JniInvocationInit(impl_, library) != 0;
-  }
-
-  // Exposes which library is actually loaded from the given name. The
-  // buffer of size PROPERTY_VALUE_MAX will be used to load the system
-  // property for the default library, if necessary. If no buffer is
-  // provided, the fallback value will be used.
-  static const char* GetLibrary(const char* library, char* buffer) {
-    return JniInvocationGetLibrary(library, buffer);
-  }
-
- private:
-  JniInvocation(const JniInvocation&) = delete;
-  JniInvocation& operator=(const JniInvocation&) = delete;
-
-  JniInvocationImpl* impl_;
-};
-
-#endif  // __cplusplus
diff --git a/include/nativehelper/libnativehelper_api.h b/include/nativehelper/libnativehelper_api.h
deleted file mode 100644
index 1efdcbd..0000000
--- a/include/nativehelper/libnativehelper_api.h
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-#pragma once
-
-#include <stdbool.h>
-#include <stddef.h>
-
-#include "jni.h"
-
-// This is the stable C API exported by libnativehelper.
-
-#ifdef __cplusplus
-extern "C" {
-#endif  // __cplusplus
-
-/* ------------------------------------ C API for JNIHelp.h ------------------------------------- */
-
-/*
- * Register one or more native methods with a particular class.  "className" looks like
- * "java/lang/String". Aborts on failure, returns 0 on success.
- */
-int jniRegisterNativeMethods(C_JNIEnv* env,
-                             const char* className,
-                             const JNINativeMethod* gMethods,
-                             int numMethods);
-
-/*
- * Throw an exception with the specified class and an optional message.
- *
- * The "className" argument will be passed directly to FindClass, which
- * takes strings with slashes (e.g. "java/lang/Object").
- *
- * If an exception is currently pending, we log a warning message and
- * clear it.
- *
- * Returns 0 on success, nonzero if something failed (e.g. the exception
- * class couldn't be found, so *an* exception will still be pending).
- *
- * Currently aborts the VM if it can't throw the exception.
- */
-int jniThrowException(C_JNIEnv* env, const char* className, const char* msg);
-
-/*
- * Throw an exception with the specified class and formatted error message.
- *
- * The "className" argument will be passed directly to FindClass, which
- * takes strings with slashes (e.g. "java/lang/Object").
- *
- * If an exception is currently pending, we log a warning message and
- * clear it.
- *
- * Returns 0 on success, nonzero if something failed (e.g. the exception
- * class couldn't be found, so *an* exception will still be pending).
- *
- * Currently aborts the VM if it can't throw the exception.
- */
-int jniThrowExceptionFmt(C_JNIEnv* env, const char* className, const char* fmt, va_list args);
-
-/*
- * Throw a java.lang.NullPointerException, with an optional message.
- */
-int jniThrowNullPointerException(C_JNIEnv* env, const char* msg);
-
-/*
- * Throw a java.lang.RuntimeException, with an optional message.
- */
-int jniThrowRuntimeException(C_JNIEnv* env, const char* msg);
-
-/*
- * Throw a java.io.IOException, generating the message from errno.
- */
-int jniThrowIOException(C_JNIEnv* env, int errnum);
-
-/*
- * Returns a new java.io.FileDescriptor for the given int fd.
- */
-jobject jniCreateFileDescriptor(C_JNIEnv* env, int fd);
-
-/*
- * Returns the int fd from a java.io.FileDescriptor.
- */
-int jniGetFDFromFileDescriptor(C_JNIEnv* env, jobject fileDescriptor);
-
-/*
- * Sets the int fd in a java.io.FileDescriptor.  Throws java.lang.NullPointerException
- * if fileDescriptor is null.
- */
-void jniSetFileDescriptorOfFD(C_JNIEnv* env, jobject fileDescriptor, int value);
-
-/*
- * Gets the managed heap array backing a java.nio.Buffer instance.
- *
- * Returns nullptr if there is no array backing.
- *
- * This method performs a JNI call to java.nio.NIOAccess.getBaseArray().
- */
-jarray jniGetNioBufferBaseArray(C_JNIEnv* env, jobject nioBuffer);
-
-/*
- * Gets the offset in bytes from the start of the managed heap array backing the buffer.
- *
- * Returns 0 if there is no array backing.
- *
- * This method performs a JNI call to java.nio.NIOAccess.getBaseArrayOffset().
- */
-jint jniGetNioBufferBaseArrayOffset(C_JNIEnv* env, jobject nioBuffer);
-
-/*
- * Gets field information from a java.nio.Buffer instance.
- *
- * Reads the |position|, |limit|, and |elementSizeShift| fields from the buffer instance.
- *
- * Returns the |address| field of the java.nio.Buffer instance which is only valid (non-zero) when
- * the buffer is backed by a direct buffer.
- */
-jlong jniGetNioBufferFields(C_JNIEnv* env,
-                            jobject nioBuffer,
-                            /*out*/jint* position,
-                            /*out*/jint* limit,
-                            /*out*/jint* elementSizeShift);
-
-/*
- * Gets the current position from a java.nio.Buffer as a pointer to memory in a fixed buffer.
- *
- * Returns 0 if |nioBuffer| is not backed by a direct buffer.
- *
- * This method reads the |address|, |position|, and |elementSizeShift| fields from the
- * java.nio.Buffer instance to calculate the pointer address for the current position.
- */
-jlong jniGetNioBufferPointer(C_JNIEnv* env, jobject nioBuffer);
-
-/*
- * Returns the reference from a java.lang.ref.Reference.
- */
-jobject jniGetReferent(C_JNIEnv* env, jobject ref);
-
-/*
- * Returns a Java String object created from UTF-16 data either from jchar or,
- * if called from C++11, char16_t (a bitwise identical distinct type).
- */
-jstring jniCreateString(C_JNIEnv* env, const jchar* unicodeChars, jsize len);
-
-/*
- * Allocates a new array for java/lang/String instances with space for |count| elements. Elements
- * are initially null.
- *
- * Returns a new array on success or nullptr in case of failure. This method raises an
- * OutOfMemoryError exception if allocation fails.
- */
-jobjectArray jniCreateStringArray(C_JNIEnv* env, size_t count);
-
-/*
- * Log a message and an exception.
- * If exception is NULL, logs the current exception in the JNI environment.
- */
-void jniLogException(C_JNIEnv* env, int priority, const char* tag, jthrowable exception);
-
-/*
- * Clear the cache of constants libnativehelper is using.
- */
-void jniUninitializeConstants();
-
-/* ---------------------------------- C API for JniInvocation.h --------------------------------- */
-
-/*
- * The JNI invocation API exists to allow a choice of library responsible for managing virtual
- * machines.
- */
-
-/*
- * Opaque structure used to hold JNI invocation internal state.
- */
-struct JniInvocationImpl;
-
-/*
- * Creates an instance of a JniInvocationImpl.
- */
-struct JniInvocationImpl* JniInvocationCreate();
-
-/*
- * Associates a library with a JniInvocationImpl instance. The library should export C symbols for
- * JNI_GetDefaultJavaVMInitArgs, JNI_CreateJavaVM and JNI_GetDefaultJavaVMInitArgs.
- *
- * The specified |library| should be the filename of a shared library. The |library| is opened with
- * dlopen(3).
- *
- * If there is an error opening the specified |library|, then function will fallback to the
- * default library "libart.so". If the fallback library is successfully used then a warning is
- * written to the Android log buffer. Use of the fallback library is not considered an error.
- *
- * If the fallback library cannot be opened or the expected symbols are not found in the library
- * opened, then an error message is written to the Android log buffer and the function returns 0.
- *
- * Returns true on success, false otherwise.
- */
-bool JniInvocationInit(struct JniInvocationImpl* instance, const char* library);
-
-/*
- * Release resources associated with JniInvocationImpl instance.
- */
-void JniInvocationDestroy(struct JniInvocationImpl* instance);
-
-/*
- * Gets the default library for JNI invocation. The default library is "libart.so". This value may
- * be overridden for debuggable builds using the persist.sys.dalvik.vm.lib.2 system property.
- *
- * The |library| argument is the preferred library to use on debuggable builds (when
- * ro.debuggable=1). If the |library| argument is nullptr, then the system preferred value will be
- * queried from persist.sys.dalvik.vm.lib.2 if the caller has provided |buffer| argument.
- *
- * The |buffer| argument is used for reading system properties in debuggable builds. It is
- * optional, but should be provisioned to be PROP_VALUE_MAX bytes if provided to ensure it is
- * large enough to hold a system property.
- *
- * Returns the filename of the invocation library determined from the inputs and system
- * properties. The returned value may be |library|, |buffer|, or a pointer to a string constant
- * "libart.so".
- */
-const char* JniInvocationGetLibrary(const char* library, char* buffer);
-
-#ifdef __cplusplus
-}
-#endif  // __cplusplus
-
diff --git a/include/nativehelper/toStringArray.h b/include/nativehelper/toStringArray.h
index 0ff45ec..4bdb297 100644
--- a/include/nativehelper/toStringArray.h
+++ b/include/nativehelper/toStringArray.h
@@ -16,12 +16,12 @@
 
 #pragma once
 
-#include "libnativehelper_api.h"
-
 #ifdef __cplusplus
 
 #include <string>
 #include <vector>
+
+#include "JNIHelp.h"
 #include "ScopedLocalRef.h"
 
 template <typename StringVisitor>
diff --git a/include_platform/nativehelper/JNIPlatformHelp.h b/include_platform/nativehelper/JNIPlatformHelp.h
new file mode 100644
index 0000000..466032b
--- /dev/null
+++ b/include_platform/nativehelper/JNIPlatformHelp.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+/*
+ * JNI helper functions.
+ *
+ * This file may be included by C or C++ code, which is trouble because jni.h
+ * uses different typedefs for JNIEnv in each language.
+ */
+#pragma once
+
+#include <sys/cdefs.h>
+
+#include <jni.h>
+
+#include <nativehelper/JNIHelp.h>
+
+__BEGIN_DECLS
+
+/*
+ * Returns a new java.io.FileDescriptor for the given int fd.
+ */
+jobject jniCreateFileDescriptor(C_JNIEnv* env, int fd);
+
+/*
+ * Returns the int fd from a java.io.FileDescriptor.
+ */
+int jniGetFDFromFileDescriptor(C_JNIEnv* env, jobject fileDescriptor);
+
+/*
+ * Sets the int fd in a java.io.FileDescriptor.  Throws java.lang.NullPointerException
+ * if fileDescriptor is null.
+ */
+void jniSetFileDescriptorOfFD(C_JNIEnv* env, jobject fileDescriptor, int value);
+
+/*
+ * Gets the managed heap array backing a java.nio.Buffer instance.
+ *
+ * Returns nullptr if there is no array backing.
+ *
+ * This method performs a JNI call to java.nio.NIOAccess.getBaseArray().
+ */
+jarray jniGetNioBufferBaseArray(C_JNIEnv* env, jobject nioBuffer);
+
+/*
+ * Gets the offset of the current buffer position in bytes from the start of the managed heap
+ * array backing the buffer.
+ *
+ * Returns 0 if there is no array backing.
+ *
+ * This method performs a JNI call to java.nio.NIOAccess.getBaseArrayOffset().
+ */
+jint jniGetNioBufferBaseArrayOffset(C_JNIEnv* env, jobject nioBuffer);
+
+/*
+ * Gets field information from a java.nio.Buffer instance.
+ *
+ * Reads the |position|, |limit|, and |elementSizeShift| fields from the buffer instance.
+ *
+ * Returns the |address| field of the java.nio.Buffer instance which is only valid (non-zero) when
+ * the buffer is backed by a direct buffer.
+ */
+jlong jniGetNioBufferFields(C_JNIEnv* env,
+                            jobject nioBuffer,
+                            /*out*/jint* position,
+                            /*out*/jint* limit,
+                            /*out*/jint* elementSizeShift);
+
+/*
+ * Gets the current position from a java.nio.Buffer as a pointer to memory in a fixed buffer.
+ *
+ * Returns 0 if |nioBuffer| is not backed by a direct buffer.
+ *
+ * This method reads the |address|, |position|, and |elementSizeShift| fields from the
+ * java.nio.Buffer instance to calculate the pointer address for the current position.
+ */
+jlong jniGetNioBufferPointer(C_JNIEnv* env, jobject nioBuffer);
+
+/*
+ * Clear the cache of constants libnativehelper is using.
+ */
+void jniUninitializeConstants();
+
+__END_DECLS
+
+/*
+ * For C++ code, we provide inlines that map to the C functions.  g++ always
+ * inlines these, even on non-optimized builds.
+ */
+#if defined(__cplusplus)
+
+inline jobject jniCreateFileDescriptor(JNIEnv* env, int fd) {
+    return jniCreateFileDescriptor(&env->functions, fd);
+}
+
+inline int jniGetFDFromFileDescriptor(JNIEnv* env, jobject fileDescriptor) {
+    return jniGetFDFromFileDescriptor(&env->functions, fileDescriptor);
+}
+
+inline void jniSetFileDescriptorOfFD(JNIEnv* env, jobject fileDescriptor, int value) {
+    jniSetFileDescriptorOfFD(&env->functions, fileDescriptor, value);
+}
+
+inline jarray jniGetNioBufferBaseArray(JNIEnv* env, jobject nioBuffer) {
+    return jniGetNioBufferBaseArray(&env->functions, nioBuffer);
+}
+
+inline jint jniGetNioBufferBaseArrayOffset(JNIEnv* env, jobject nioBuffer) {
+    return jniGetNioBufferBaseArrayOffset(&env->functions, nioBuffer);
+}
+
+inline jlong jniGetNioBufferFields(JNIEnv* env, jobject nioBuffer,
+                                   jint* position, jint* limit, jint* elementSizeShift) {
+    return jniGetNioBufferFields(&env->functions, nioBuffer,
+                                 position, limit, elementSizeShift);
+}
+
+inline jlong jniGetNioBufferPointer(JNIEnv* env, jobject nioBuffer) {
+    return jniGetNioBufferPointer(&env->functions, nioBuffer);
+}
+
+#endif  // defined(__cplusplus)
diff --git a/include_platform/nativehelper/JniInvocation.h b/include_platform/nativehelper/JniInvocation.h
new file mode 100644
index 0000000..746eaed
--- /dev/null
+++ b/include_platform/nativehelper/JniInvocation.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+
+#include <stdbool.h>
+
+__BEGIN_DECLS
+
+/*
+ * The JNI invocation API exists to allow a choice of library responsible for managing virtual
+ * machines.
+ */
+
+/*
+ * Opaque structure used to hold JNI invocation internal state.
+ */
+struct JniInvocationImpl;
+
+/*
+ * Creates an instance of a JniInvocationImpl.
+ */
+struct JniInvocationImpl* JniInvocationCreate();
+
+/*
+ * Associates a library with a JniInvocationImpl instance. The library should export C symbols for
+ * JNI_GetDefaultJavaVMInitArgs, JNI_CreateJavaVM and JNI_GetDefaultJavaVMInitArgs.
+ *
+ * The specified |library| should be the filename of a shared library. The |library| is opened with
+ * dlopen(3).
+ *
+ * If there is an error opening the specified |library|, then function will fallback to the
+ * default library "libart.so". If the fallback library is successfully used then a warning is
+ * written to the Android log buffer. Use of the fallback library is not considered an error.
+ *
+ * If the fallback library cannot be opened or the expected symbols are not found in the library
+ * opened, then an error message is written to the Android log buffer and the function returns 0.
+ *
+ * Returns true on success, false otherwise.
+ */
+bool JniInvocationInit(struct JniInvocationImpl* instance, const char* library);
+
+/*
+ * Release resources associated with JniInvocationImpl instance.
+ */
+void JniInvocationDestroy(struct JniInvocationImpl* instance);
+
+/*
+ * Gets the default library for JNI invocation. The default library is "libart.so". This value may
+ * be overridden for debuggable builds using the persist.sys.dalvik.vm.lib.2 system property.
+ *
+ * The |library| argument is the preferred library to use on debuggable builds (when
+ * ro.debuggable=1). If the |library| argument is nullptr, then the system preferred value will be
+ * queried from persist.sys.dalvik.vm.lib.2 if the caller has provided |buffer| argument.
+ *
+ * The |buffer| argument is used for reading system properties in debuggable builds. It is
+ * optional, but should be provisioned to be PROP_VALUE_MAX bytes if provided to ensure it is
+ * large enough to hold a system property.
+ *
+ * Returns the filename of the invocation library determined from the inputs and system
+ * properties. The returned value may be |library|, |buffer|, or a pointer to a string constant
+ * "libart.so".
+ */
+const char* JniInvocationGetLibrary(const char* library, char* buffer);
+
+__END_DECLS
+
+#ifdef __cplusplus
+
+// JniInvocation adds a layer of indirection for applications using
+// the JNI invocation API to allow the JNI implementation to be
+// selected dynamically. Apps can specify a specific implementation to
+// be used by calling InitJniInvocation. If this is not done, the
+// library will chosen based on the value of Android system property
+// persist.sys.dalvik.vm.lib on the device, and otherwise fall back to
+// a hard-coded default implementation.
+class JniInvocation final {
+ public:
+  JniInvocation() {
+    impl_ = JniInvocationCreate();
+  }
+
+  ~JniInvocation() {
+    JniInvocationDestroy(impl_);
+  }
+
+  // Initialize JNI invocation API. library should specify a valid
+  // shared library for opening via dlopen providing a JNI invocation
+  // implementation, or null to allow defaulting via
+  // persist.sys.dalvik.vm.lib.
+  bool Init(const char* library) {
+    return JniInvocationInit(impl_, library) != 0;
+  }
+
+  // Exposes which library is actually loaded from the given name. The
+  // buffer of size PROPERTY_VALUE_MAX will be used to load the system
+  // property for the default library, if necessary. If no buffer is
+  // provided, the fallback value will be used.
+  static const char* GetLibrary(const char* library, char* buffer) {
+    return JniInvocationGetLibrary(library, buffer);
+  }
+
+ private:
+  JniInvocation(const JniInvocation&) = delete;
+  JniInvocation& operator=(const JniInvocation&) = delete;
+
+  JniInvocationImpl* impl_;
+};
+
+#endif  // __cplusplus
diff --git a/platform_include/nativehelper/detail/signature_checker.h b/include_platform_header_only/nativehelper/detail/signature_checker.h
similarity index 100%
rename from platform_include/nativehelper/detail/signature_checker.h
rename to include_platform_header_only/nativehelper/detail/signature_checker.h
diff --git a/platform_include/nativehelper/jni_macros.h b/include_platform_header_only/nativehelper/jni_macros.h
similarity index 100%
rename from platform_include/nativehelper/jni_macros.h
rename to include_platform_header_only/nativehelper/jni_macros.h
diff --git a/libnativehelper.map.txt b/libnativehelper.map.txt
index 672f269..822edad 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_1 {
+LIBNATIVEHELPER_30 {
   global:
     JNI_GetDefaultJavaVMInitArgs;
     JNI_CreateJavaVM;