Merge "Remove setsockoptGroupSourceReq and StructGroupSourceReq"
diff --git a/Android.bp b/Android.bp
index 30a9c59..6d3ab86 100644
--- a/Android.bp
+++ b/Android.bp
@@ -19,6 +19,12 @@
     vendor_available: true,
 }
 
+cc_library_headers {
+    name: "jni_platform_headers",
+    host_supported: true,
+    export_include_dirs: ["platform_include"],
+}
+
 cc_library {
     name: "libnativehelper",
     host_supported: true,
@@ -40,13 +46,12 @@
         },
     },
 
-    header_libs: ["jni_headers"],
+    header_libs: ["jni_headers", "jni_platform_headers"],
     export_header_lib_headers: ["jni_headers"],
 
     shared_libs: [
         "liblog",
     ],
-    clang: true,
     cflags: [
         "-Werror",
         "-fvisibility=protected",
@@ -63,10 +68,12 @@
 
 cc_library_shared {
     name: "libnativehelper_compat_libc++",
-    clang: true,
-    local_include_dirs: ["include/nativehelper"],
-    export_include_dirs: ["include/nativehelper"],
+    export_include_dirs: [
+        "include",
+        "include/nativehelper", // TODO(b/63762847): remove
+    ],
     cflags: ["-Werror"],
+    include_dirs: ["libnativehelper/platform_include"],
     srcs: [
         "JNIHelp.cpp",
         "JniConstants.cpp",
@@ -82,9 +89,9 @@
 
 ndk_headers {
     name: "ndk_jni.h",
-    from: "include/nativehelper",
+    from: "include_jni",
     to: "",
-    srcs: ["include/nativehelper/jni.h"],
+    srcs: ["include_jni/jni.h"],
     license: "NOTICE",
 }
 
diff --git a/AsynchronousCloseMonitor.cpp b/AsynchronousCloseMonitor.cpp
index 1815580..95de317 100644
--- a/AsynchronousCloseMonitor.cpp
+++ b/AsynchronousCloseMonitor.cpp
@@ -16,7 +16,7 @@
 
 #define LOG_TAG "AsynchronousCloseMonitor"
 
-#include "AsynchronousCloseMonitor.h"
+#include <nativehelper/AsynchronousCloseMonitor.h>
 #include "cutils/log.h"
 
 #include <errno.h>
diff --git a/JNIHelp-priv.h b/JNIHelp-priv.h
new file mode 100644
index 0000000..ce350a5
--- /dev/null
+++ b/JNIHelp-priv.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2017 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.
+ */
+
+#ifndef NATIVEHELPER_JNIHELP_PRIV_H_
+#define NATIVEHELPER_JNIHELP_PRIV_H_
+
+namespace android {
+
+void ClearJNIHelpLocalCache();
+
+}  // namespace android
+
+#endif  // JNIHELP_PRIV
diff --git a/JNIHelp.cpp b/JNIHelp.cpp
index 54012b8..9c6cd74 100644
--- a/JNIHelp.cpp
+++ b/JNIHelp.cpp
@@ -23,8 +23,8 @@
 
 #define LOG_TAG "JNIHelp"
 
-#include "JniConstants.h"
-#include "JNIHelp.h"
+#include <nativehelper/JniConstants.h>
+#include <nativehelper/JNIHelp.h>
 #include "ALog-priv.h"
 
 #include <stdio.h>
@@ -34,6 +34,55 @@
 
 #include <string>
 
+namespace {
+
+// java.io.FileDescriptor.descriptor.
+jfieldID fileDescriptorDescriptorField = nullptr;
+
+// void java.io.FileDescriptor.<init>().
+jmethodID fileDescriptorInitMethod = nullptr;
+// Object java.lang.ref.Reference.get()
+jmethodID referenceGetMethod = nullptr;
+
+jfieldID FindField(JNIEnv* env, jclass klass, const char* name, const char* desc) {
+    jfieldID result = env->GetFieldID(klass, name, desc);
+    if (result == NULL) {
+        ALOGV("failed to find field '%s:%s'", name, desc);
+        abort();
+    }
+    return result;
+}
+
+jmethodID FindMethod(JNIEnv* env, jclass klass, const char* name, const char* signature) {
+    jmethodID result = env->GetMethodID(klass, name, signature);
+    if (result == NULL) {
+        ALOGV("failed to find method '%s%s'", name, signature);
+        abort();
+    }
+    return result;
+}
+
+void InitFieldsAndMethods(JNIEnv* env) {
+    JniConstants::init(env);  // Ensure that classes are cached.
+    fileDescriptorDescriptorField = FindField(env, JniConstants::fileDescriptorClass, "descriptor",
+            "I");
+    fileDescriptorInitMethod = FindMethod(env, JniConstants::fileDescriptorClass, "<init>", "()V");
+    referenceGetMethod = FindMethod(env, JniConstants::referenceClass, "get",
+            "()Ljava/lang/Object;");
+}
+
+}
+
+namespace android {
+
+void ClearJNIHelpLocalCache() {
+    fileDescriptorDescriptorField = nullptr;
+    fileDescriptorInitMethod = nullptr;
+    referenceGetMethod = nullptr;
+}
+
+}
+
 /**
  * Equivalent to ScopedLocalRef, but for C_JNIEnv instead. (And slightly more powerful.)
  */
@@ -326,9 +375,11 @@
 
 jobject jniCreateFileDescriptor(C_JNIEnv* env, int fd) {
     JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
-    JniConstants::init(e);
-    static jmethodID ctor = e->GetMethodID(JniConstants::fileDescriptorClass, "<init>", "()V");
-    jobject fileDescriptor = (*env)->NewObject(e, JniConstants::fileDescriptorClass, ctor);
+    if (fileDescriptorInitMethod == nullptr) {
+        InitFieldsAndMethods(e);
+    }
+    jobject fileDescriptor = (*env)->NewObject(e, JniConstants::fileDescriptorClass,
+            fileDescriptorInitMethod);
     // NOTE: NewObject ensures that an OutOfMemoryError will be seen by the Java
     // caller if the alloc fails, so we just return NULL when that happens.
     if (fileDescriptor != NULL)  {
@@ -339,10 +390,12 @@
 
 int jniGetFDFromFileDescriptor(C_JNIEnv* env, jobject fileDescriptor) {
     JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
-    JniConstants::init(e);
-    static jfieldID fid = e->GetFieldID(JniConstants::fileDescriptorClass, "descriptor", "I");
+    if (fileDescriptorDescriptorField == nullptr) {
+        InitFieldsAndMethods(e);
+    }
     if (fileDescriptor != NULL) {
-        return (*env)->GetIntField(e, fileDescriptor, fid);
+        return (*env)->GetIntField(e, fileDescriptor,
+                fileDescriptorDescriptorField);
     } else {
         return -1;
     }
@@ -350,16 +403,18 @@
 
 void jniSetFileDescriptorOfFD(C_JNIEnv* env, jobject fileDescriptor, int value) {
     JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
-    JniConstants::init(e);
-    static jfieldID fid = e->GetFieldID(JniConstants::fileDescriptorClass, "descriptor", "I");
-    (*env)->SetIntField(e, fileDescriptor, fid, value);
+    if (fileDescriptorDescriptorField == nullptr) {
+        InitFieldsAndMethods(e);
+    }
+    (*env)->SetIntField(e, fileDescriptor, fileDescriptorDescriptorField, value);
 }
 
 jobject jniGetReferent(C_JNIEnv* env, jobject ref) {
     JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
-    JniConstants::init(e);
-    static jmethodID get = e->GetMethodID(JniConstants::referenceClass, "get", "()Ljava/lang/Object;");
-    return (*env)->CallObjectMethod(e, ref, get);
+    if (referenceGetMethod == nullptr) {
+        InitFieldsAndMethods(e);
+    }
+    return (*env)->CallObjectMethod(e, ref, referenceGetMethod);
 }
 
 jstring jniCreateString(C_JNIEnv* env, const jchar* unicodeChars, jsize len) {
diff --git a/JniConstants.cpp b/JniConstants.cpp
index c637d82..3ac554b 100644
--- a/JniConstants.cpp
+++ b/JniConstants.cpp
@@ -17,8 +17,10 @@
 #define LOG_TAG "JniConstants"
 
 #include "ALog-priv.h"
-#include "JniConstants.h"
-#include "ScopedLocalRef.h"
+#include "JNIHelp-priv.h"
+#include <nativehelper/JniConstants.h>
+#include <nativehelper/JniConstants-priv.h>
+#include <nativehelper/ScopedLocalRef.h>
 
 #include <stdlib.h>
 
@@ -136,3 +138,12 @@
 
     g_constants_initialized = true;
 }
+
+namespace android {
+
+void ClearJniConstantsCache() {
+    g_constants_initialized = false;
+    ClearJNIHelpLocalCache();
+}
+
+}
diff --git a/JniInvocation.cpp b/JniInvocation.cpp
index b869914..031dcb3 100644
--- a/JniInvocation.cpp
+++ b/JniInvocation.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "JniInvocation.h"
+#include <nativehelper/JniInvocation.h>
 
 #include <dlfcn.h>
 #include <stdlib.h>
diff --git a/include/nativehelper/ScopedLocalRef.h b/include/nativehelper/ScopedLocalRef.h
index 6e30eb3..4018f20 100644
--- a/include/nativehelper/ScopedLocalRef.h
+++ b/include/nativehelper/ScopedLocalRef.h
@@ -17,9 +17,9 @@
 #ifndef SCOPED_LOCAL_REF_H_included
 #define SCOPED_LOCAL_REF_H_included
 
-#include "jni.h"
+#include <cstddef>
 
-#include <stddef.h>
+#include "jni.h"
 #include "JNIHelp.h"  // for DISALLOW_COPY_AND_ASSIGN.
 
 // A smart pointer that deletes a JNI local reference when it goes out of scope.
@@ -52,8 +52,40 @@
         return mLocalRef;
     }
 
+// Some better C++11 support.
+#if __cplusplus >= 201103L
+    // Move constructor.
+    ScopedLocalRef(ScopedLocalRef&& s) : mEnv(s.mEnv), mLocalRef(s.release()) {
+    }
+
+    explicit ScopedLocalRef(JNIEnv* env) : mEnv(env), mLocalRef(nullptr) {
+    }
+
+    // We do not expose an empty constructor as it can easily lead to errors
+    // using common idioms, e.g.:
+    //   ScopedLocalRef<...> ref;
+    //   ref.reset(...);
+
+    // Move assignment operator.
+    ScopedLocalRef& operator=(ScopedLocalRef&& s) {
+        reset(s.release());
+        mEnv = s.mEnv;
+        return *this;
+    }
+
+    // Allows "if (scoped_ref == nullptr)"
+    bool operator==(std::nullptr_t) const {
+        return mLocalRef == nullptr;
+    }
+
+    // Allows "if (scoped_ref != nullptr)"
+    bool operator!=(std::nullptr_t) const {
+        return mLocalRef != nullptr;
+    }
+#endif
+
 private:
-    JNIEnv* const mEnv;
+    JNIEnv* mEnv;
     T mLocalRef;
 
     DISALLOW_COPY_AND_ASSIGN(ScopedLocalRef);
diff --git a/include/nativehelper/ScopedUtfChars.h b/include/nativehelper/ScopedUtfChars.h
index 9cfa9a0..aa8489d 100644
--- a/include/nativehelper/ScopedUtfChars.h
+++ b/include/nativehelper/ScopedUtfChars.h
@@ -22,30 +22,53 @@
 
 // A smart pointer that provides read-only access to a Java string's UTF chars.
 // Unlike GetStringUTFChars, we throw NullPointerException rather than abort if
-// passed a null jstring, and c_str will return NULL.
+// passed a null jstring, and c_str will return nullptr.
 // This makes the correct idiom very simple:
 //
 //   ScopedUtfChars name(env, java_name);
-//   if (name.c_str() == NULL) {
-//     return NULL;
+//   if (name.c_str() == nullptr) {
+//     return nullptr;
 //   }
 class ScopedUtfChars {
  public:
   ScopedUtfChars(JNIEnv* env, jstring s) : env_(env), string_(s) {
-    if (s == NULL) {
-      utf_chars_ = NULL;
-      jniThrowNullPointerException(env, NULL);
+    if (s == nullptr) {
+      utf_chars_ = nullptr;
+      jniThrowNullPointerException(env, nullptr);
     } else {
-      utf_chars_ = env->GetStringUTFChars(s, NULL);
+      utf_chars_ = env->GetStringUTFChars(s, nullptr);
     }
   }
 
+  ScopedUtfChars(ScopedUtfChars&& rhs) :
+      env_(rhs.env_), string_(rhs.string_), utf_chars_(rhs.utf_chars_) {
+    rhs.env_ = nullptr;
+    rhs.string_ = nullptr;
+    rhs.utf_chars_ = nullptr;
+  }
+
   ~ScopedUtfChars() {
     if (utf_chars_) {
       env_->ReleaseStringUTFChars(string_, utf_chars_);
     }
   }
 
+  ScopedUtfChars& operator=(ScopedUtfChars&& rhs) {
+    if (this != &rhs) {
+      // Delete the currently owned UTF chars.
+      this->~ScopedUtfChars();
+
+      // Move the rhs ScopedUtfChars and zero it out.
+      env_ = rhs.env_;
+      string_ = rhs.string_;
+      utf_chars_ = rhs.utf_chars_;
+      rhs.env_ = nullptr;
+      rhs.string_ = nullptr;
+      rhs.utf_chars_ = nullptr;
+    }
+    return *this;
+  }
+
   const char* c_str() const {
     return utf_chars_;
   }
@@ -59,8 +82,8 @@
   }
 
  private:
-  JNIEnv* const env_;
-  const jstring string_;
+  JNIEnv* env_;
+  jstring string_;
   const char* utf_chars_;
 
   DISALLOW_COPY_AND_ASSIGN(ScopedUtfChars);
diff --git a/include_deprecated/JNIHelp.h b/include_deprecated/JNIHelp.h
new file mode 120000
index 0000000..d4cf162
--- /dev/null
+++ b/include_deprecated/JNIHelp.h
@@ -0,0 +1 @@
+../include/nativehelper/JNIHelp.h
\ No newline at end of file
diff --git a/include_deprecated/UniquePtr.h b/include_deprecated/UniquePtr.h
new file mode 120000
index 0000000..e47c2a2
--- /dev/null
+++ b/include_deprecated/UniquePtr.h
@@ -0,0 +1 @@
+../include/nativehelper/UniquePtr.h
\ No newline at end of file
diff --git a/include_deprecated/jni.h b/include_deprecated/jni.h
new file mode 120000
index 0000000..0f70e26
--- /dev/null
+++ b/include_deprecated/jni.h
@@ -0,0 +1 @@
+../include_jni/jni.h
\ No newline at end of file
diff --git a/include_jni/jni.h b/include_jni/jni.h
deleted file mode 120000
index 88d1a00..0000000
--- a/include_jni/jni.h
+++ /dev/null
@@ -1 +0,0 @@
-../include/nativehelper/jni.h
\ No newline at end of file
diff --git a/include/nativehelper/jni.h b/include_jni/jni.h
similarity index 100%
rename from include/nativehelper/jni.h
rename to include_jni/jni.h
diff --git a/platform_include/nativehelper/JniConstants-priv.h b/platform_include/nativehelper/JniConstants-priv.h
new file mode 100644
index 0000000..c4cba7c
--- /dev/null
+++ b/platform_include/nativehelper/JniConstants-priv.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2017 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.
+ */
+
+#ifndef NATIVEHELPER_PLATFORM_INCLUDE_NATIVEHELPER_JNICONSTANTS_PRIV_H_
+#define NATIVEHELPER_PLATFORM_INCLUDE_NATIVEHELPER_JNICONSTANTS_PRIV_H_
+
+namespace android {
+
+void ClearJniConstantsCache();
+
+}  // namespace android
+
+#endif  // NATIVEHELPER_PLATFORM_INCLUDE_NATIVEHELPER_JNICONSTANTS_PRIV_H_
diff --git a/tests/Android.bp b/tests/Android.bp
index 523b419..21d4073 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -4,7 +4,6 @@
     name: "JniInvocation_test",
     test_suites: ["device-tests"],
     host_supported: true,
-    clang: true,
     srcs: ["JniInvocation_test.cpp"],
     shared_libs: ["libnativehelper"],
 }
diff --git a/tests/JniInvocation_test.cpp b/tests/JniInvocation_test.cpp
index 7a73c70..1467cb3 100644
--- a/tests/JniInvocation_test.cpp
+++ b/tests/JniInvocation_test.cpp
@@ -16,7 +16,7 @@
 
 #define LOG_TAG "NativeBridge_test"
 
-#include <JniInvocation.h>
+#include <nativehelper/JniInvocation.h>
 #include <gtest/gtest.h>
 
 
diff --git a/toStringArray.cpp b/toStringArray.cpp
index f2b0add..3ccc053 100644
--- a/toStringArray.cpp
+++ b/toStringArray.cpp
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#include "JniConstants.h"
-#include "toStringArray.h"
+#include <nativehelper/JniConstants.h>
+#include <nativehelper/toStringArray.h>
 
 jobjectArray newStringArray(JNIEnv* env, size_t count) {
     return env->NewObjectArray(count, JniConstants::stringClass, NULL);