1 /*
2 * Copyright 2015 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 // Android's FindClass() is tricky because the app-specific ClassLoader is not
12 // consulted when there is no app-specific frame on the stack (i.e. when called
13 // from a thread created from native C++ code). These helper functions provide a
14 // workaround for this.
15 // http://developer.android.com/training/articles/perf-jni.html#faq_FindClass
16
17 #ifndef SDK_ANDROID_NATIVE_API_JNI_JAVA_TYPES_H_
18 #define SDK_ANDROID_NATIVE_API_JNI_JAVA_TYPES_H_
19
20 #include <jni.h>
21
22 #include <map>
23 #include <memory>
24 #include <string>
25 #include <vector>
26
27 #include "absl/types/optional.h"
28 #include "api/array_view.h"
29 #include "rtc_base/checks.h"
30 #include "rtc_base/thread_checker.h"
31 #include "sdk/android/native_api/jni/scoped_java_ref.h"
32
33 // Abort the process if |jni| has a Java exception pending.
34 // This macros uses the comma operator to execute ExceptionDescribe
35 // and ExceptionClear ignoring their return values and sending ""
36 // to the error stream.
37 #define CHECK_EXCEPTION(jni) \
38 RTC_CHECK(!jni->ExceptionCheck()) \
39 << (jni->ExceptionDescribe(), jni->ExceptionClear(), "")
40
41 namespace webrtc {
42
43 // ---------------
44 // -- Utilities --
45 // ---------------
46
47 // Provides a convenient way to iterate over a Java Iterable using the
48 // C++ range-for loop.
49 // E.g. for (jobject value : Iterable(jni, j_iterable)) { ... }
50 // Note: Since Java iterators cannot be duplicated, the iterator class is not
51 // copyable to prevent creating multiple C++ iterators that refer to the same
52 // Java iterator.
53 class Iterable {
54 public:
55 Iterable(JNIEnv* jni, const JavaRef<jobject>& iterable);
56 Iterable(Iterable&& other);
57
58 ~Iterable();
59
60 class Iterator {
61 public:
62 // Creates an iterator representing the end of any collection.
63 Iterator();
64 // Creates an iterator pointing to the beginning of the specified
65 // collection.
66 Iterator(JNIEnv* jni, const JavaRef<jobject>& iterable);
67
68 // Move constructor - necessary to be able to return iterator types from
69 // functions.
70 Iterator(Iterator&& other);
71
72 ~Iterator();
73
74 // Move assignment should not be used.
75 Iterator& operator=(Iterator&&) = delete;
76
77 // Advances the iterator one step.
78 Iterator& operator++();
79
80 // Removes the element the iterator is pointing to. Must still advance the
81 // iterator afterwards.
82 void Remove();
83
84 // Provides a way to compare the iterator with itself and with the end
85 // iterator.
86 // Note: all other comparison results are undefined, just like for C++ input
87 // iterators.
88 bool operator==(const Iterator& other);
89 bool operator!=(const Iterator& other) { return !(*this == other); }
90 ScopedJavaLocalRef<jobject>& operator*();
91
92 private:
93 bool AtEnd() const;
94
95 JNIEnv* jni_ = nullptr;
96 ScopedJavaLocalRef<jobject> iterator_;
97 ScopedJavaLocalRef<jobject> value_;
98 rtc::ThreadChecker thread_checker_;
99
100 RTC_DISALLOW_COPY_AND_ASSIGN(Iterator);
101 };
102
begin()103 Iterable::Iterator begin() { return Iterable::Iterator(jni_, iterable_); }
end()104 Iterable::Iterator end() { return Iterable::Iterator(); }
105
106 private:
107 JNIEnv* jni_;
108 ScopedJavaLocalRef<jobject> iterable_;
109
110 RTC_DISALLOW_COPY_AND_ASSIGN(Iterable);
111 };
112
113 // Returns true if |obj| == null in Java.
114 bool IsNull(JNIEnv* jni, const JavaRef<jobject>& obj);
115
116 // Returns the name of a Java enum.
117 std::string GetJavaEnumName(JNIEnv* jni, const JavaRef<jobject>& j_enum);
118
119 Iterable GetJavaMapEntrySet(JNIEnv* jni, const JavaRef<jobject>& j_map);
120 ScopedJavaLocalRef<jobject> GetJavaMapEntryKey(JNIEnv* jni,
121 const JavaRef<jobject>& j_entry);
122 ScopedJavaLocalRef<jobject> GetJavaMapEntryValue(
123 JNIEnv* jni,
124 const JavaRef<jobject>& j_entry);
125
126 // --------------------------------------------------------
127 // -- Methods for converting Java types to native types. --
128 // --------------------------------------------------------
129
130 int64_t JavaToNativeLong(JNIEnv* env, const JavaRef<jobject>& j_long);
131
132 absl::optional<bool> JavaToNativeOptionalBool(JNIEnv* jni,
133 const JavaRef<jobject>& boolean);
134 absl::optional<double> JavaToNativeOptionalDouble(
135 JNIEnv* jni,
136 const JavaRef<jobject>& j_double);
137 absl::optional<int32_t> JavaToNativeOptionalInt(
138 JNIEnv* jni,
139 const JavaRef<jobject>& integer);
140
141 // Given a (UTF-16) jstring return a new UTF-8 native string.
142 std::string JavaToNativeString(JNIEnv* jni, const JavaRef<jstring>& j_string);
143
144 template <typename T, typename Convert>
JavaToNativeVector(JNIEnv * env,const JavaRef<jobjectArray> & j_container,Convert convert)145 std::vector<T> JavaToNativeVector(JNIEnv* env,
146 const JavaRef<jobjectArray>& j_container,
147 Convert convert) {
148 std::vector<T> container;
149 const size_t size = env->GetArrayLength(j_container.obj());
150 container.reserve(size);
151 for (size_t i = 0; i < size; ++i) {
152 container.emplace_back(convert(
153 env, ScopedJavaLocalRef<jobject>(
154 env, env->GetObjectArrayElement(j_container.obj(), i))));
155 }
156 CHECK_EXCEPTION(env) << "Error during JavaToNativeVector";
157 return container;
158 }
159
160 template <typename T, typename Java_T = jobject, typename Convert>
JavaListToNativeVector(JNIEnv * env,const JavaRef<jobject> & j_list,Convert convert)161 std::vector<T> JavaListToNativeVector(JNIEnv* env,
162 const JavaRef<jobject>& j_list,
163 Convert convert) {
164 std::vector<T> native_list;
165 if (!j_list.is_null()) {
166 for (ScopedJavaLocalRef<jobject>& j_item : Iterable(env, j_list)) {
167 native_list.emplace_back(
168 convert(env, static_java_ref_cast<Java_T>(env, j_item)));
169 }
170 CHECK_EXCEPTION(env) << "Error during JavaListToNativeVector";
171 }
172 return native_list;
173 }
174
175 template <typename Key, typename T, typename Convert>
JavaToNativeMap(JNIEnv * env,const JavaRef<jobject> & j_map,Convert convert)176 std::map<Key, T> JavaToNativeMap(JNIEnv* env,
177 const JavaRef<jobject>& j_map,
178 Convert convert) {
179 std::map<Key, T> container;
180 for (auto const& j_entry : GetJavaMapEntrySet(env, j_map)) {
181 container.emplace(convert(env, GetJavaMapEntryKey(env, j_entry),
182 GetJavaMapEntryValue(env, j_entry)));
183 }
184 return container;
185 }
186
187 // Converts Map<String, String> to std::map<std::string, std::string>.
188 std::map<std::string, std::string> JavaToNativeStringMap(
189 JNIEnv* env,
190 const JavaRef<jobject>& j_map);
191
192 // --------------------------------------------------------
193 // -- Methods for converting native types to Java types. --
194 // --------------------------------------------------------
195
196 ScopedJavaLocalRef<jobject> NativeToJavaBoolean(JNIEnv* env, bool b);
197 ScopedJavaLocalRef<jobject> NativeToJavaDouble(JNIEnv* env, double d);
198 ScopedJavaLocalRef<jobject> NativeToJavaInteger(JNIEnv* jni, int32_t i);
199 ScopedJavaLocalRef<jobject> NativeToJavaLong(JNIEnv* env, int64_t u);
200 ScopedJavaLocalRef<jstring> NativeToJavaString(JNIEnv* jni, const char* str);
201 ScopedJavaLocalRef<jstring> NativeToJavaString(JNIEnv* jni,
202 const std::string& str);
203
204 ScopedJavaLocalRef<jobject> NativeToJavaDouble(
205 JNIEnv* jni,
206 const absl::optional<double>& optional_double);
207 ScopedJavaLocalRef<jobject> NativeToJavaInteger(
208 JNIEnv* jni,
209 const absl::optional<int32_t>& optional_int);
210 ScopedJavaLocalRef<jstring> NativeToJavaString(
211 JNIEnv* jni,
212 const absl::optional<std::string>& str);
213
214 // Helper function for converting std::vector<T> into a Java array.
215 template <typename T, typename Convert>
NativeToJavaObjectArray(JNIEnv * env,const std::vector<T> & container,jclass clazz,Convert convert)216 ScopedJavaLocalRef<jobjectArray> NativeToJavaObjectArray(
217 JNIEnv* env,
218 const std::vector<T>& container,
219 jclass clazz,
220 Convert convert) {
221 ScopedJavaLocalRef<jobjectArray> j_container(
222 env, env->NewObjectArray(container.size(), clazz, nullptr));
223 int i = 0;
224 for (const T& element : container) {
225 env->SetObjectArrayElement(j_container.obj(), i,
226 convert(env, element).obj());
227 ++i;
228 }
229 return j_container;
230 }
231
232 ScopedJavaLocalRef<jbyteArray> NativeToJavaByteArray(
233 JNIEnv* env,
234 rtc::ArrayView<int8_t> container);
235 ScopedJavaLocalRef<jintArray> NativeToJavaIntArray(
236 JNIEnv* env,
237 rtc::ArrayView<int32_t> container);
238
239 std::vector<int8_t> JavaToNativeByteArray(JNIEnv* env,
240 const JavaRef<jbyteArray>& jarray);
241 std::vector<int32_t> JavaToNativeIntArray(JNIEnv* env,
242 const JavaRef<jintArray>& jarray);
243
244 ScopedJavaLocalRef<jobjectArray> NativeToJavaBooleanArray(
245 JNIEnv* env,
246 const std::vector<bool>& container);
247 ScopedJavaLocalRef<jobjectArray> NativeToJavaDoubleArray(
248 JNIEnv* env,
249 const std::vector<double>& container);
250 ScopedJavaLocalRef<jobjectArray> NativeToJavaIntegerArray(
251 JNIEnv* env,
252 const std::vector<int32_t>& container);
253 ScopedJavaLocalRef<jobjectArray> NativeToJavaLongArray(
254 JNIEnv* env,
255 const std::vector<int64_t>& container);
256 ScopedJavaLocalRef<jobjectArray> NativeToJavaStringArray(
257 JNIEnv* env,
258 const std::vector<std::string>& container);
259
260 // This is a helper class for NativeToJavaList(). Use that function instead of
261 // using this class directly.
262 class JavaListBuilder {
263 public:
264 explicit JavaListBuilder(JNIEnv* env);
265 ~JavaListBuilder();
266 void add(const JavaRef<jobject>& element);
java_list()267 ScopedJavaLocalRef<jobject> java_list() { return j_list_; }
268
269 private:
270 JNIEnv* env_;
271 ScopedJavaLocalRef<jobject> j_list_;
272 };
273
274 template <typename C, typename Convert>
NativeToJavaList(JNIEnv * env,const C & container,Convert convert)275 ScopedJavaLocalRef<jobject> NativeToJavaList(JNIEnv* env,
276 const C& container,
277 Convert convert) {
278 JavaListBuilder builder(env);
279 for (const auto& e : container)
280 builder.add(convert(env, e));
281 return builder.java_list();
282 }
283
284 // This is a helper class for NativeToJavaMap(). Use that function instead of
285 // using this class directly.
286 class JavaMapBuilder {
287 public:
288 explicit JavaMapBuilder(JNIEnv* env);
289 ~JavaMapBuilder();
290 void put(const JavaRef<jobject>& key, const JavaRef<jobject>& value);
GetJavaMap()291 ScopedJavaLocalRef<jobject> GetJavaMap() { return j_map_; }
292
293 private:
294 JNIEnv* env_;
295 ScopedJavaLocalRef<jobject> j_map_;
296 };
297
298 template <typename C, typename Convert>
NativeToJavaMap(JNIEnv * env,const C & container,Convert convert)299 ScopedJavaLocalRef<jobject> NativeToJavaMap(JNIEnv* env,
300 const C& container,
301 Convert convert) {
302 JavaMapBuilder builder(env);
303 for (const auto& e : container) {
304 const auto key_value_pair = convert(env, e);
305 builder.put(key_value_pair.first, key_value_pair.second);
306 }
307 return builder.GetJavaMap();
308 }
309
310 template <typename C>
NativeToJavaStringMap(JNIEnv * env,const C & container)311 ScopedJavaLocalRef<jobject> NativeToJavaStringMap(JNIEnv* env,
312 const C& container) {
313 JavaMapBuilder builder(env);
314 for (const auto& e : container) {
315 const auto key_value_pair = std::make_pair(
316 NativeToJavaString(env, e.first), NativeToJavaString(env, e.second));
317 builder.put(key_value_pair.first, key_value_pair.second);
318 }
319 return builder.GetJavaMap();
320 }
321
322 // Return a |jlong| that will correctly convert back to |ptr|. This is needed
323 // because the alternative (of silently passing a 32-bit pointer to a vararg
324 // function expecting a 64-bit param) picks up garbage in the high 32 bits.
325 jlong NativeToJavaPointer(void* ptr);
326
327 // ------------------------
328 // -- Deprecated methods --
329 // ------------------------
330
331 // Deprecated. Use JavaToNativeString.
JavaToStdString(JNIEnv * jni,const JavaRef<jstring> & j_string)332 inline std::string JavaToStdString(JNIEnv* jni,
333 const JavaRef<jstring>& j_string) {
334 return JavaToNativeString(jni, j_string);
335 }
336
337 // Deprecated. Use scoped jobjects instead.
JavaToStdString(JNIEnv * jni,jstring j_string)338 inline std::string JavaToStdString(JNIEnv* jni, jstring j_string) {
339 return JavaToStdString(jni, JavaParamRef<jstring>(j_string));
340 }
341
342 // Deprecated. Use JavaListToNativeVector<std::string, jstring> instead.
343 // Given a List of (UTF-16) jstrings
344 // return a new vector of UTF-8 native strings.
345 std::vector<std::string> JavaToStdVectorStrings(JNIEnv* jni,
346 const JavaRef<jobject>& list);
347
348 // Deprecated. Use JavaToNativeStringMap instead.
349 // Parses Map<String, String> to std::map<std::string, std::string>.
JavaToStdMapStrings(JNIEnv * jni,const JavaRef<jobject> & j_map)350 inline std::map<std::string, std::string> JavaToStdMapStrings(
351 JNIEnv* jni,
352 const JavaRef<jobject>& j_map) {
353 return JavaToNativeStringMap(jni, j_map);
354 }
355
356 // Deprecated. Use scoped jobjects instead.
JavaToStdMapStrings(JNIEnv * jni,jobject j_map)357 inline std::map<std::string, std::string> JavaToStdMapStrings(JNIEnv* jni,
358 jobject j_map) {
359 return JavaToStdMapStrings(jni, JavaParamRef<jobject>(j_map));
360 }
361
362 } // namespace webrtc
363
364 #endif // SDK_ANDROID_NATIVE_API_JNI_JAVA_TYPES_H_
365