xref: /aosp_15_r20/external/webrtc/sdk/android/native_api/jni/java_types.h (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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 "api/sequence_checker.h"
30 #include "rtc_base/checks.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   Iterable(const Iterable&) = delete;
61   Iterable& operator=(const Iterable&) = delete;
62 
63   class Iterator {
64    public:
65     // Creates an iterator representing the end of any collection.
66     Iterator();
67     // Creates an iterator pointing to the beginning of the specified
68     // collection.
69     Iterator(JNIEnv* jni, const JavaRef<jobject>& iterable);
70 
71     // Move constructor - necessary to be able to return iterator types from
72     // functions.
73     Iterator(Iterator&& other);
74 
75     ~Iterator();
76 
77     Iterator(const Iterator&) = delete;
78     Iterator& operator=(const Iterator&) = delete;
79 
80     // Move assignment should not be used.
81     Iterator& operator=(Iterator&&) = delete;
82 
83     // Advances the iterator one step.
84     Iterator& operator++();
85 
86     // Removes the element the iterator is pointing to. Must still advance the
87     // iterator afterwards.
88     void Remove();
89 
90     // Provides a way to compare the iterator with itself and with the end
91     // iterator.
92     // Note: all other comparison results are undefined, just like for C++ input
93     // iterators.
94     bool operator==(const Iterator& other);
95     bool operator!=(const Iterator& other) { return !(*this == other); }
96     ScopedJavaLocalRef<jobject>& operator*();
97 
98    private:
99     bool AtEnd() const;
100 
101     JNIEnv* jni_ = nullptr;
102     ScopedJavaLocalRef<jobject> iterator_;
103     ScopedJavaLocalRef<jobject> value_;
104     SequenceChecker thread_checker_;
105   };
106 
begin()107   Iterable::Iterator begin() { return Iterable::Iterator(jni_, iterable_); }
end()108   Iterable::Iterator end() { return Iterable::Iterator(); }
109 
110  private:
111   JNIEnv* jni_;
112   ScopedJavaLocalRef<jobject> iterable_;
113 };
114 
115 // Returns true if `obj` == null in Java.
116 bool IsNull(JNIEnv* jni, const JavaRef<jobject>& obj);
117 
118 // Returns the name of a Java enum.
119 std::string GetJavaEnumName(JNIEnv* jni, const JavaRef<jobject>& j_enum);
120 
121 Iterable GetJavaMapEntrySet(JNIEnv* jni, const JavaRef<jobject>& j_map);
122 ScopedJavaLocalRef<jobject> GetJavaMapEntryKey(JNIEnv* jni,
123                                                const JavaRef<jobject>& j_entry);
124 ScopedJavaLocalRef<jobject> GetJavaMapEntryValue(
125     JNIEnv* jni,
126     const JavaRef<jobject>& j_entry);
127 
128 // --------------------------------------------------------
129 // -- Methods for converting Java types to native types. --
130 // --------------------------------------------------------
131 
132 int64_t JavaToNativeLong(JNIEnv* env, const JavaRef<jobject>& j_long);
133 
134 absl::optional<bool> JavaToNativeOptionalBool(JNIEnv* jni,
135                                               const JavaRef<jobject>& boolean);
136 absl::optional<double> JavaToNativeOptionalDouble(
137     JNIEnv* jni,
138     const JavaRef<jobject>& j_double);
139 absl::optional<int32_t> JavaToNativeOptionalInt(
140     JNIEnv* jni,
141     const JavaRef<jobject>& integer);
142 
143 // Given a (UTF-16) jstring return a new UTF-8 native string.
144 std::string JavaToNativeString(JNIEnv* jni, const JavaRef<jstring>& j_string);
145 
146 template <typename T, typename Convert>
JavaToNativeVector(JNIEnv * env,const JavaRef<jobjectArray> & j_container,Convert convert)147 std::vector<T> JavaToNativeVector(JNIEnv* env,
148                                   const JavaRef<jobjectArray>& j_container,
149                                   Convert convert) {
150   std::vector<T> container;
151   const size_t size = env->GetArrayLength(j_container.obj());
152   container.reserve(size);
153   for (size_t i = 0; i < size; ++i) {
154     container.emplace_back(convert(
155         env, ScopedJavaLocalRef<jobject>(
156                  env, env->GetObjectArrayElement(j_container.obj(), i))));
157   }
158   CHECK_EXCEPTION(env) << "Error during JavaToNativeVector";
159   return container;
160 }
161 
162 template <typename T, typename Java_T = jobject, typename Convert>
JavaListToNativeVector(JNIEnv * env,const JavaRef<jobject> & j_list,Convert convert)163 std::vector<T> JavaListToNativeVector(JNIEnv* env,
164                                       const JavaRef<jobject>& j_list,
165                                       Convert convert) {
166   std::vector<T> native_list;
167   if (!j_list.is_null()) {
168     for (ScopedJavaLocalRef<jobject>& j_item : Iterable(env, j_list)) {
169       native_list.emplace_back(
170           convert(env, static_java_ref_cast<Java_T>(env, j_item)));
171     }
172     CHECK_EXCEPTION(env) << "Error during JavaListToNativeVector";
173   }
174   return native_list;
175 }
176 
177 template <typename Key, typename T, typename Convert>
JavaToNativeMap(JNIEnv * env,const JavaRef<jobject> & j_map,Convert convert)178 std::map<Key, T> JavaToNativeMap(JNIEnv* env,
179                                  const JavaRef<jobject>& j_map,
180                                  Convert convert) {
181   std::map<Key, T> container;
182   for (auto const& j_entry : GetJavaMapEntrySet(env, j_map)) {
183     container.emplace(convert(env, GetJavaMapEntryKey(env, j_entry),
184                               GetJavaMapEntryValue(env, j_entry)));
185   }
186   return container;
187 }
188 
189 // Converts Map<String, String> to std::map<std::string, std::string>.
190 std::map<std::string, std::string> JavaToNativeStringMap(
191     JNIEnv* env,
192     const JavaRef<jobject>& j_map);
193 
194 // --------------------------------------------------------
195 // -- Methods for converting native types to Java types. --
196 // --------------------------------------------------------
197 
198 ScopedJavaLocalRef<jobject> NativeToJavaBoolean(JNIEnv* env, bool b);
199 ScopedJavaLocalRef<jobject> NativeToJavaDouble(JNIEnv* env, double d);
200 ScopedJavaLocalRef<jobject> NativeToJavaInteger(JNIEnv* jni, int32_t i);
201 ScopedJavaLocalRef<jobject> NativeToJavaLong(JNIEnv* env, int64_t u);
202 ScopedJavaLocalRef<jstring> NativeToJavaString(JNIEnv* jni, const char* str);
203 ScopedJavaLocalRef<jstring> NativeToJavaString(JNIEnv* jni,
204                                                const std::string& str);
205 
206 ScopedJavaLocalRef<jobject> NativeToJavaDouble(
207     JNIEnv* jni,
208     const absl::optional<double>& optional_double);
209 ScopedJavaLocalRef<jobject> NativeToJavaInteger(
210     JNIEnv* jni,
211     const absl::optional<int32_t>& optional_int);
212 ScopedJavaLocalRef<jstring> NativeToJavaString(
213     JNIEnv* jni,
214     const absl::optional<std::string>& str);
215 
216 // Helper function for converting std::vector<T> into a Java array.
217 template <typename T, typename Convert>
NativeToJavaObjectArray(JNIEnv * env,const std::vector<T> & container,jclass clazz,Convert convert)218 ScopedJavaLocalRef<jobjectArray> NativeToJavaObjectArray(
219     JNIEnv* env,
220     const std::vector<T>& container,
221     jclass clazz,
222     Convert convert) {
223   ScopedJavaLocalRef<jobjectArray> j_container(
224       env, env->NewObjectArray(container.size(), clazz, nullptr));
225   int i = 0;
226   for (const T& element : container) {
227     env->SetObjectArrayElement(j_container.obj(), i,
228                                convert(env, element).obj());
229     ++i;
230   }
231   return j_container;
232 }
233 
234 ScopedJavaLocalRef<jbyteArray> NativeToJavaByteArray(
235     JNIEnv* env,
236     rtc::ArrayView<int8_t> container);
237 ScopedJavaLocalRef<jintArray> NativeToJavaIntArray(
238     JNIEnv* env,
239     rtc::ArrayView<int32_t> container);
240 
241 std::vector<int8_t> JavaToNativeByteArray(JNIEnv* env,
242                                           const JavaRef<jbyteArray>& jarray);
243 std::vector<int32_t> JavaToNativeIntArray(JNIEnv* env,
244                                           const JavaRef<jintArray>& jarray);
245 
246 ScopedJavaLocalRef<jobjectArray> NativeToJavaBooleanArray(
247     JNIEnv* env,
248     const std::vector<bool>& container);
249 ScopedJavaLocalRef<jobjectArray> NativeToJavaDoubleArray(
250     JNIEnv* env,
251     const std::vector<double>& container);
252 ScopedJavaLocalRef<jobjectArray> NativeToJavaIntegerArray(
253     JNIEnv* env,
254     const std::vector<int32_t>& container);
255 ScopedJavaLocalRef<jobjectArray> NativeToJavaLongArray(
256     JNIEnv* env,
257     const std::vector<int64_t>& container);
258 ScopedJavaLocalRef<jobjectArray> NativeToJavaStringArray(
259     JNIEnv* env,
260     const std::vector<std::string>& container);
261 
262 // This is a helper class for NativeToJavaList(). Use that function instead of
263 // using this class directly.
264 class JavaListBuilder {
265  public:
266   explicit JavaListBuilder(JNIEnv* env);
267   ~JavaListBuilder();
268   void add(const JavaRef<jobject>& element);
java_list()269   ScopedJavaLocalRef<jobject> java_list() { return j_list_; }
270 
271  private:
272   JNIEnv* env_;
273   ScopedJavaLocalRef<jobject> j_list_;
274 };
275 
276 template <typename C, typename Convert>
NativeToJavaList(JNIEnv * env,const C & container,Convert convert)277 ScopedJavaLocalRef<jobject> NativeToJavaList(JNIEnv* env,
278                                              const C& container,
279                                              Convert convert) {
280   JavaListBuilder builder(env);
281   for (const auto& e : container)
282     builder.add(convert(env, e));
283   return builder.java_list();
284 }
285 
286 // This is a helper class for NativeToJavaMap(). Use that function instead of
287 // using this class directly.
288 class JavaMapBuilder {
289  public:
290   explicit JavaMapBuilder(JNIEnv* env);
291   ~JavaMapBuilder();
292   void put(const JavaRef<jobject>& key, const JavaRef<jobject>& value);
GetJavaMap()293   ScopedJavaLocalRef<jobject> GetJavaMap() { return j_map_; }
294 
295  private:
296   JNIEnv* env_;
297   ScopedJavaLocalRef<jobject> j_map_;
298 };
299 
300 template <typename C, typename Convert>
NativeToJavaMap(JNIEnv * env,const C & container,Convert convert)301 ScopedJavaLocalRef<jobject> NativeToJavaMap(JNIEnv* env,
302                                             const C& container,
303                                             Convert convert) {
304   JavaMapBuilder builder(env);
305   for (const auto& e : container) {
306     const auto key_value_pair = convert(env, e);
307     builder.put(key_value_pair.first, key_value_pair.second);
308   }
309   return builder.GetJavaMap();
310 }
311 
312 template <typename C>
NativeToJavaStringMap(JNIEnv * env,const C & container)313 ScopedJavaLocalRef<jobject> NativeToJavaStringMap(JNIEnv* env,
314                                                   const C& container) {
315   JavaMapBuilder builder(env);
316   for (const auto& e : container) {
317     const auto key_value_pair = std::make_pair(
318         NativeToJavaString(env, e.first), NativeToJavaString(env, e.second));
319     builder.put(key_value_pair.first, key_value_pair.second);
320   }
321   return builder.GetJavaMap();
322 }
323 
324 // Return a `jlong` that will correctly convert back to `ptr`.  This is needed
325 // because the alternative (of silently passing a 32-bit pointer to a vararg
326 // function expecting a 64-bit param) picks up garbage in the high 32 bits.
327 jlong NativeToJavaPointer(void* ptr);
328 
329 // ------------------------
330 // -- Deprecated methods --
331 // ------------------------
332 
333 // Deprecated. Use JavaToNativeString.
JavaToStdString(JNIEnv * jni,const JavaRef<jstring> & j_string)334 inline std::string JavaToStdString(JNIEnv* jni,
335                                    const JavaRef<jstring>& j_string) {
336   return JavaToNativeString(jni, j_string);
337 }
338 
339 // Deprecated. Use scoped jobjects instead.
JavaToStdString(JNIEnv * jni,jstring j_string)340 inline std::string JavaToStdString(JNIEnv* jni, jstring j_string) {
341   return JavaToStdString(jni, JavaParamRef<jstring>(j_string));
342 }
343 
344 // Deprecated. Use JavaListToNativeVector<std::string, jstring> instead.
345 // Given a List of (UTF-16) jstrings
346 // return a new vector of UTF-8 native strings.
347 std::vector<std::string> JavaToStdVectorStrings(JNIEnv* jni,
348                                                 const JavaRef<jobject>& list);
349 
350 // Deprecated. Use JavaToNativeStringMap instead.
351 // Parses Map<String, String> to std::map<std::string, std::string>.
JavaToStdMapStrings(JNIEnv * jni,const JavaRef<jobject> & j_map)352 inline std::map<std::string, std::string> JavaToStdMapStrings(
353     JNIEnv* jni,
354     const JavaRef<jobject>& j_map) {
355   return JavaToNativeStringMap(jni, j_map);
356 }
357 
358 // Deprecated. Use scoped jobjects instead.
JavaToStdMapStrings(JNIEnv * jni,jobject j_map)359 inline std::map<std::string, std::string> JavaToStdMapStrings(JNIEnv* jni,
360                                                               jobject j_map) {
361   return JavaToStdMapStrings(jni, JavaParamRef<jobject>(j_map));
362 }
363 
364 }  // namespace webrtc
365 
366 #endif  // SDK_ANDROID_NATIVE_API_JNI_JAVA_TYPES_H_
367