• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 // Utility class that provides similar calls like JNIEnv, but performs
18 // additional checks on them, so that it's harder to use them incorrectly.
19 
20 #ifndef LIBTEXTCLASSIFIER_UTILS_JAVA_JNI_HELPER_H_
21 #define LIBTEXTCLASSIFIER_UTILS_JAVA_JNI_HELPER_H_
22 
23 #include <jni.h>
24 
25 #include <string>
26 
27 #include "utils/base/status.h"
28 #include "utils/base/statusor.h"
29 #include "utils/java/jni-base.h"
30 
31 #define TC3_ENSURE_LOCAL_CAPACITY_OR_RETURN             \
32   if (!EnsureLocalCapacity(env, 1)) {                   \
33     TC3_LOG(ERROR) << "EnsureLocalCapacity(1) failed."; \
34     return {Status::UNKNOWN};                           \
35   }
36 
37 #define TC3_NO_EXCEPTION_OR_RETURN      \
38   if (JniExceptionCheckAndClear(env)) { \
39     return {Status::UNKNOWN};           \
40   }
41 
42 #define TC3_NOT_NULL_OR_RETURN \
43   if (result == nullptr) {     \
44     return {Status::UNKNOWN};  \
45   }
46 
47 #define TC3_DEFINE_VARIADIC_SCOPED_LOCAL_REF_ENV_METHOD(                   \
48     METHOD_NAME, RETURN_TYPE, INPUT_TYPE, POST_CHECK)                      \
49   template <typename T = RETURN_TYPE>                                      \
50   static StatusOr<ScopedLocalRef<T>> METHOD_NAME(                          \
51       JNIEnv* env, INPUT_TYPE object, jmethodID method_id, ...) {          \
52     TC3_ENSURE_LOCAL_CAPACITY_OR_RETURN;                                   \
53                                                                            \
54     va_list args;                                                          \
55     va_start(args, method_id);                                             \
56     ScopedLocalRef<T> result(                                              \
57         reinterpret_cast<T>(env->METHOD_NAME##V(object, method_id, args)), \
58         env);                                                              \
59     POST_CHECK                                                             \
60     va_end(args);                                                          \
61                                                                            \
62     TC3_NO_EXCEPTION_OR_RETURN;                                            \
63     return result;                                                         \
64   }
65 
66 #define TC3_JNI_NO_CHECK \
67   {}
68 
69 namespace libtextclassifier3 {
70 
71 class JniHelper {
72  public:
73   // Misc methods.
74   static StatusOr<ScopedLocalRef<jclass>> FindClass(JNIEnv* env,
75                                                     const char* class_name);
76 
77   template <typename T = jobject>
78   static StatusOr<ScopedLocalRef<T>> GetObjectArrayElement(JNIEnv* env,
79                                                            jobjectArray array,
80                                                            jsize index);
81   static StatusOr<jmethodID> GetMethodID(JNIEnv* env, jclass clazz,
82                                          const char* method_name,
83                                          const char* return_type);
84 
85   static StatusOr<ScopedLocalRef<jobject>> GetStaticObjectField(
86       JNIEnv* env, jclass class_name, jfieldID field_id);
87 
88   // New* methods.
89   TC3_DEFINE_VARIADIC_SCOPED_LOCAL_REF_ENV_METHOD(NewObject, jobject, jclass,
90                                                   TC3_NOT_NULL_OR_RETURN);
91   static StatusOr<ScopedLocalRef<jobjectArray>> NewObjectArray(
92       JNIEnv* env, jsize length, jclass element_class,
93       jobject initial_element = nullptr);
94   static StatusOr<ScopedLocalRef<jbyteArray>> NewByteArray(JNIEnv* env,
95                                                            jsize length);
96   static StatusOr<ScopedLocalRef<jintArray>> NewIntArray(JNIEnv* env,
97                                                          jsize length);
98   static StatusOr<ScopedLocalRef<jstring>> NewStringUTF(JNIEnv* env,
99                                                         const char* bytes);
100   static StatusOr<ScopedLocalRef<jfloatArray>> NewFloatArray(JNIEnv* env,
101                                                              jsize length);
102 
103   static StatusOr<jsize> GetArrayLength(JNIEnv* env, jarray jinput_fragments);
104 
105   static Status SetObjectArrayElement(JNIEnv* env, jobjectArray array,
106                                       jsize index, jobject val);
107 
108   // Call* methods.
109   TC3_DEFINE_VARIADIC_SCOPED_LOCAL_REF_ENV_METHOD(CallObjectMethod, jobject,
110                                                   jobject, TC3_JNI_NO_CHECK);
111   TC3_DEFINE_VARIADIC_SCOPED_LOCAL_REF_ENV_METHOD(CallStaticObjectMethod,
112                                                   jobject, jclass,
113                                                   TC3_JNI_NO_CHECK);
114   static Status CallVoidMethod(JNIEnv* env, jobject object, jmethodID method_id,
115                                ...);
116   static StatusOr<bool> CallBooleanMethod(JNIEnv* env, jobject object,
117                                           jmethodID method_id, ...);
118   static StatusOr<int32> CallIntMethod(JNIEnv* env, jobject object,
119                                        jmethodID method_id, ...);
120   static StatusOr<int64> CallLongMethod(JNIEnv* env, jobject object,
121                                         jmethodID method_id, ...);
122   static StatusOr<float> CallFloatMethod(JNIEnv* env, jobject object,
123                                          jmethodID method_id, ...);
124   static StatusOr<double> CallDoubleMethod(JNIEnv* env, jobject object,
125                                            jmethodID method_id, ...);
126 
127   template <class T>
128   static StatusOr<T> CallStaticIntMethod(JNIEnv* env, jclass clazz,
129                                          jmethodID method_id, ...);
130 };
131 
132 template <typename T>
GetObjectArrayElement(JNIEnv * env,jobjectArray array,jsize index)133 StatusOr<ScopedLocalRef<T>> JniHelper::GetObjectArrayElement(JNIEnv* env,
134                                                              jobjectArray array,
135                                                              jsize index) {
136   TC3_ENSURE_LOCAL_CAPACITY_OR_RETURN;
137   ScopedLocalRef<T> result(
138       reinterpret_cast<T>(env->GetObjectArrayElement(array, index)), env);
139 
140   TC3_NO_EXCEPTION_OR_RETURN;
141   return result;
142 }
143 
144 template <class T>
CallStaticIntMethod(JNIEnv * env,jclass clazz,jmethodID method_id,...)145 StatusOr<T> JniHelper::CallStaticIntMethod(JNIEnv* env, jclass clazz,
146                                            jmethodID method_id, ...) {
147   va_list args;
148   va_start(args, method_id);
149   jint result = env->CallStaticIntMethodV(clazz, method_id, args);
150   va_end(args);
151 
152   TC3_NO_EXCEPTION_OR_RETURN;
153   return result;
154 }
155 
156 }  // namespace libtextclassifier3
157 
158 #endif  // LIBTEXTCLASSIFIER_UTILS_JAVA_JNI_HELPER_H_
159