• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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