Android: Add header for generated JNI code

This header will be included from generated JNI code, and acts as a
bridge between JNI types in WebRTC and Chromium.

Bug: webrtc:8278
Change-Id: I88331d26315aa8b258aaaaa26d82324660d648b5
NOPRESUBMIT: True
Reviewed-on: https://webrtc-review.googlesource.com/3441
Commit-Queue: Magnus Jedvert <magjed@webrtc.org>
Reviewed-by: Sami Kalliomäki <sakal@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#19974}
diff --git a/sdk/android/BUILD.gn b/sdk/android/BUILD.gn
index c30f047..d313771 100644
--- a/sdk/android/BUILD.gn
+++ b/sdk/android/BUILD.gn
@@ -39,6 +39,8 @@
     "src/jni/classreferenceholder.cc",
     "src/jni/classreferenceholder.h",
     "src/jni/jni_common.cc",
+    "src/jni/jni_generator_helper.cc",
+    "src/jni/jni_generator_helper.h",
     "src/jni/jni_helpers.cc",
     "src/jni/jni_helpers.h",
     "src/jni/pc/audio_jni.h",
diff --git a/sdk/android/src/jni/jni_generator_helper.cc b/sdk/android/src/jni/jni_generator_helper.cc
new file mode 100644
index 0000000..3bc9b05
--- /dev/null
+++ b/sdk/android/src/jni/jni_generator_helper.cc
@@ -0,0 +1,102 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "sdk/android/src/jni/jni_generator_helper.h"
+
+#include "rtc_base/atomicops.h"
+
+namespace base {
+namespace android {
+
+namespace {
+// JNIEnv-helper methods that RTC_CHECK success: no Java exception thrown and
+// found object/class/method/field is non-null.
+jclass GetClass(JNIEnv* jni, const char* class_name) {
+  jclass clazz = jni->FindClass(class_name);
+  CHECK_EXCEPTION(jni) << "error during FindClass: " << class_name;
+  RTC_CHECK(clazz) << class_name;
+  return clazz;
+}
+}  // namespace
+
+// If |atomic_class_id| set, it'll return immediately. Otherwise, it will look
+// up the class and store it. If there's a race, we take care to only store one
+// global reference (and the duplicated effort will happen only once).
+jclass LazyGetClass(JNIEnv* env,
+                    const char* class_name,
+                    base::subtle::AtomicWord* atomic_class_id) {
+  static_assert(sizeof(base::subtle::AtomicWord) >= sizeof(jclass),
+                "AtomicWord can't be smaller than jclass");
+  base::subtle::AtomicWord value =
+      rtc::AtomicOps::AcquireLoadPtr(atomic_class_id);
+  if (value)
+    return reinterpret_cast<jclass>(value);
+  jclass clazz =
+      static_cast<jclass>(env->NewGlobalRef(GetClass(env, class_name)));
+  base::subtle::AtomicWord null_aw = nullptr;
+  base::subtle::AtomicWord cas_result = rtc::AtomicOps::CompareAndSwapPtr(
+      atomic_class_id, null_aw,
+      reinterpret_cast<base::subtle::AtomicWord>(clazz));
+  if (cas_result == null_aw) {
+    // We sucessfully stored |clazz| in |atomic_class_id|, so we are
+    // intentionally leaking the global ref since it's now stored there.
+    return clazz;
+  } else {
+    // Some other thread came before us and stored a global pointer in
+    // |atomic_class_id|. Relase our global ref and return the ref from the
+    // other thread.
+    env->DeleteGlobalRef(clazz);
+    return reinterpret_cast<jclass>(cas_result);
+  }
+}
+
+// If |atomic_method_id| set, it'll return immediately. Otherwise, it will look
+// up the method id and store it. If there's a race, it's ok since the values
+// are the same (and the duplicated effort will happen only once).
+template <MethodID::Type type>
+jmethodID MethodID::LazyGet(JNIEnv* env,
+                            jclass clazz,
+                            const char* method_name,
+                            const char* jni_signature,
+                            base::subtle::AtomicWord* atomic_method_id) {
+  static_assert(sizeof(base::subtle::AtomicWord) >= sizeof(jmethodID),
+                "AtomicWord can't be smaller than jMethodID");
+  base::subtle::AtomicWord value =
+      rtc::AtomicOps::AcquireLoadPtr(atomic_method_id);
+  if (value)
+    return reinterpret_cast<jmethodID>(value);
+  jmethodID id =
+      (type == MethodID::TYPE_STATIC)
+          ? webrtc::jni::GetStaticMethodID(env, clazz, method_name,
+                                           jni_signature)
+          : webrtc::jni::GetMethodID(env, clazz, method_name, jni_signature);
+  rtc::AtomicOps::CompareAndSwapPtr(
+      atomic_method_id, base::subtle::AtomicWord(nullptr),
+      reinterpret_cast<base::subtle::AtomicWord>(id));
+  return id;
+}
+
+// Various template instantiations.
+template jmethodID MethodID::LazyGet<MethodID::TYPE_STATIC>(
+    JNIEnv* env,
+    jclass clazz,
+    const char* method_name,
+    const char* jni_signature,
+    base::subtle::AtomicWord* atomic_method_id);
+
+template jmethodID MethodID::LazyGet<MethodID::TYPE_INSTANCE>(
+    JNIEnv* env,
+    jclass clazz,
+    const char* method_name,
+    const char* jni_signature,
+    base::subtle::AtomicWord* atomic_method_id);
+
+}  // namespace android
+}  // namespace base
diff --git a/sdk/android/src/jni/jni_generator_helper.h b/sdk/android/src/jni/jni_generator_helper.h
new file mode 100644
index 0000000..76d73e6
--- /dev/null
+++ b/sdk/android/src/jni/jni_generator_helper.h
@@ -0,0 +1,107 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+// Do not include this file directly. It's intended to be used only by the JNI
+// generation script. We are exporting types in strange namespaces in order to
+// be compatible with the generated code targeted for Chromium. We are bypassing
+// the wrapping done by Chromium's JniIntWrapper, JavaRef, and
+// ScopedJavaLocalRef, and use raw jobjects instead.
+
+#ifndef SDK_ANDROID_SRC_JNI_JNI_GENERATOR_HELPER_H_
+#define SDK_ANDROID_SRC_JNI_JNI_GENERATOR_HELPER_H_
+
+#include "sdk/android/src/jni/jni_helpers.h"
+
+#define CHECK_CLAZZ(env, jcaller, clazz, ...) RTC_DCHECK(clazz);
+
+#define BASE_EXPORT
+#define JNI_REGISTRATION_EXPORT __attribute__((visibility("default")))
+
+namespace jni_generator {
+inline void CheckException(JNIEnv* env) {
+  CHECK_EXCEPTION(env);
+}
+}  // namespace jni_generator
+
+namespace {
+// Bypass JniIntWrapper.
+// TODO(magjed): Start using Chromium's JniIntWrapper.
+typedef jint JniIntWrapper;
+inline jint as_jint(JniIntWrapper wrapper) {
+  return wrapper;
+}
+}  // namespace
+
+namespace base {
+
+namespace subtle {
+// This needs to be a type that is big enough to store a jobject/jclass.
+typedef void* AtomicWord;
+}  // namespace subtle
+
+namespace android {
+
+// Implement JavaRef and ScopedJavaLocalRef as a shallow wrapper on top of a
+// jobject/jclass, with no scoped destruction.
+// TODO(magjed): Start using Chromium's scoped Java refs.
+template <typename T>
+class JavaRef {
+ public:
+  JavaRef() {}
+  JavaRef(JNIEnv* env, T obj) : obj_(obj) {}
+  T obj() const { return obj_; }
+
+  // Implicit on purpose.
+  JavaRef(const T& obj) : obj_(obj) {}
+  operator T() const { return obj_; }
+
+ private:
+  T obj_;
+};
+
+// TODO(magjed): This looks weird, but it is safe. We don't use DeleteLocalRef
+// in WebRTC, we use ScopedLocalRefFrame instead. We should probably switch to
+// using DeleteLocalRef though.
+template <typename T>
+using ScopedJavaLocalRef = JavaRef<T>;
+
+// This function will initialize |atomic_class_id| to contain a global ref to
+// the given class, and will return that ref on subsequent calls. The caller is
+// responsible to zero-initialize |atomic_class_id|. It's fine to
+// simultaneously call this on multiple threads referencing the same
+// |atomic_method_id|.
+jclass LazyGetClass(JNIEnv* env,
+                    const char* class_name,
+                    base::subtle::AtomicWord* atomic_class_id);
+
+// This class is a wrapper for JNIEnv Get(Static)MethodID.
+class MethodID {
+ public:
+  enum Type {
+    TYPE_STATIC,
+    TYPE_INSTANCE,
+  };
+
+  // This function will initialize |atomic_method_id| to contain a ref to
+  // the given method, and will return that ref on subsequent calls. The caller
+  // is responsible to zero-initialize |atomic_method_id|. It's fine to
+  // simultaneously call this on multiple threads referencing the same
+  // |atomic_method_id|.
+  template <Type type>
+  static jmethodID LazyGet(JNIEnv* env,
+                           jclass clazz,
+                           const char* method_name,
+                           const char* jni_signature,
+                           base::subtle::AtomicWord* atomic_method_id);
+};
+
+}  // namespace android
+}  // namespace base
+
+#endif  // SDK_ANDROID_SRC_JNI_JNI_GENERATOR_HELPER_H_