1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/android/jni_array.h"
6
7 #include "base/android/jni_android.h"
8 #include "base/android/jni_string.h"
9 #include "base/check_op.h"
10 #include "base/containers/extend.h"
11 #include "base/containers/heap_array.h"
12 #include "base/numerics/safe_conversions.h"
13
14 namespace base::android {
15
16 UNSAFE_BUFFER_USAGE ScopedJavaLocalRef<jbyteArray>
ToJavaByteArray(JNIEnv * env,const uint8_t * bytes,size_t len)17 ToJavaByteArray(JNIEnv* env, const uint8_t* bytes, size_t len) {
18 return ToJavaByteArray(
19 env,
20 // SAFETY: The caller must provide a valid pointer and length.
21 UNSAFE_BUFFERS(base::span(bytes, len)));
22 }
23
ToJavaByteArray(JNIEnv * env,base::span<const uint8_t> bytes)24 ScopedJavaLocalRef<jbyteArray> ToJavaByteArray(
25 JNIEnv* env,
26 base::span<const uint8_t> bytes) {
27 jbyteArray byte_array = env->NewByteArray(checked_cast<jsize>(bytes.size()));
28 CheckException(env);
29 DCHECK(byte_array);
30
31 static_assert(sizeof(jbyte) == sizeof(uint8_t));
32 static_assert(alignof(jbyte) <= alignof(uint8_t));
33 env->SetByteArrayRegion(byte_array, jsize{0},
34 checked_cast<jsize>(bytes.size()),
35 reinterpret_cast<const jbyte*>(bytes.data()));
36 CheckException(env);
37
38 return ScopedJavaLocalRef<jbyteArray>(env, byte_array);
39 }
40
ToJavaByteArray(JNIEnv * env,std::string_view str)41 ScopedJavaLocalRef<jbyteArray> ToJavaByteArray(JNIEnv* env,
42 std::string_view str) {
43 return ToJavaByteArray(env, base::as_byte_span(str));
44 }
45
ToJavaBooleanArray(JNIEnv * env,const std::vector<bool> & bools)46 ScopedJavaLocalRef<jbooleanArray> ToJavaBooleanArray(
47 JNIEnv* env,
48 const std::vector<bool>& bools) {
49 // Make an actual array of types equivalent to `bool`.
50 auto actual_bools = HeapArray<bool>::Uninit(bools.size());
51 std::ranges::copy(bools, actual_bools.begin());
52 return ToJavaBooleanArray(env, actual_bools);
53 }
54
ToJavaBooleanArray(JNIEnv * env,span<const bool> bools)55 ScopedJavaLocalRef<jbooleanArray> ToJavaBooleanArray(JNIEnv* env,
56 span<const bool> bools) {
57 jbooleanArray boolean_array =
58 env->NewBooleanArray(checked_cast<jsize>(bools.size()));
59 CheckException(env);
60 DCHECK(boolean_array);
61
62 static_assert(sizeof(jboolean) == sizeof(bool));
63 static_assert(alignof(jboolean) <= alignof(bool));
64 env->SetBooleanArrayRegion(boolean_array, jsize{0},
65 checked_cast<jsize>(bools.size()),
66 reinterpret_cast<const jboolean*>(bools.data()));
67 CheckException(env);
68
69 return ScopedJavaLocalRef<jbooleanArray>(env, boolean_array);
70 }
71
ToJavaIntArray(JNIEnv * env,base::span<const int32_t> ints)72 ScopedJavaLocalRef<jintArray> ToJavaIntArray(JNIEnv* env,
73 base::span<const int32_t> ints) {
74 jintArray int_array = env->NewIntArray(checked_cast<jsize>(ints.size()));
75 CheckException(env);
76 DCHECK(int_array);
77
78 static_assert(sizeof(jint) == sizeof(int32_t));
79 static_assert(alignof(jint) <= alignof(int32_t));
80 env->SetIntArrayRegion(int_array, jsize{0}, checked_cast<jsize>(ints.size()),
81 reinterpret_cast<const jint*>(ints.data()));
82 CheckException(env);
83
84 return ScopedJavaLocalRef<jintArray>(env, int_array);
85 }
86
87 // Returns a new Java long array converted from the given int64_t array.
ToJavaLongArray(JNIEnv * env,base::span<const int64_t> longs)88 BASE_EXPORT ScopedJavaLocalRef<jlongArray> ToJavaLongArray(
89 JNIEnv* env,
90 base::span<const int64_t> longs) {
91 jlongArray long_array = env->NewLongArray(checked_cast<jsize>(longs.size()));
92 CheckException(env);
93 DCHECK(long_array);
94
95 static_assert(sizeof(jlong) == sizeof(int64_t));
96 static_assert(alignof(jlong) <= alignof(int64_t));
97 env->SetLongArrayRegion(long_array, jsize{0},
98 checked_cast<jsize>(longs.size()),
99 reinterpret_cast<const jlong*>(longs.data()));
100 CheckException(env);
101
102 return ScopedJavaLocalRef<jlongArray>(env, long_array);
103 }
104
ToJavaFloatArray(JNIEnv * env,base::span<const float> floats)105 BASE_EXPORT ScopedJavaLocalRef<jfloatArray> ToJavaFloatArray(
106 JNIEnv* env,
107 base::span<const float> floats) {
108 jfloatArray float_array =
109 env->NewFloatArray(checked_cast<jsize>(floats.size()));
110 CheckException(env);
111 DCHECK(float_array);
112
113 static_assert(sizeof(jfloat) == sizeof(float));
114 static_assert(alignof(jfloat) <= alignof(float));
115 env->SetFloatArrayRegion(float_array, jsize{0},
116 checked_cast<jsize>(floats.size()),
117 reinterpret_cast<const jfloat*>(floats.data()));
118 CheckException(env);
119
120 return ScopedJavaLocalRef<jfloatArray>(env, float_array);
121 }
122
ToJavaDoubleArray(JNIEnv * env,base::span<const double> doubles)123 BASE_EXPORT ScopedJavaLocalRef<jdoubleArray> ToJavaDoubleArray(
124 JNIEnv* env,
125 base::span<const double> doubles) {
126 jdoubleArray double_array =
127 env->NewDoubleArray(checked_cast<jsize>(doubles.size()));
128 CheckException(env);
129 DCHECK(double_array);
130
131 static_assert(sizeof(jdouble) == sizeof(double));
132 static_assert(alignof(jdouble) <= alignof(double));
133 env->SetDoubleArrayRegion(double_array, jsize{0},
134 checked_cast<jsize>(doubles.size()),
135 reinterpret_cast<const jdouble*>(doubles.data()));
136 CheckException(env);
137
138 return ScopedJavaLocalRef<jdoubleArray>(env, double_array);
139 }
140
ToJavaArrayOfObjects(JNIEnv * env,jclass clazz,base::span<const ScopedJavaLocalRef<jobject>> v)141 BASE_EXPORT ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfObjects(
142 JNIEnv* env,
143 jclass clazz,
144 base::span<const ScopedJavaLocalRef<jobject>> v) {
145 jobjectArray joa =
146 env->NewObjectArray(checked_cast<jsize>(v.size()), clazz, nullptr);
147 CheckException(env);
148
149 for (size_t i = 0; i < v.size(); ++i) {
150 env->SetObjectArrayElement(joa, checked_cast<jsize>(i), v[i].obj());
151 }
152 return ScopedJavaLocalRef<jobjectArray>(env, joa);
153 }
154
ToJavaArrayOfObjects(JNIEnv * env,base::span<const ScopedJavaLocalRef<jobject>> v)155 BASE_EXPORT ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfObjects(
156 JNIEnv* env,
157 base::span<const ScopedJavaLocalRef<jobject>> v) {
158 return ToJavaArrayOfObjects(env, jni_zero::g_object_class, v);
159 }
160
ToJavaArrayOfObjects(JNIEnv * env,base::span<const ScopedJavaGlobalRef<jobject>> v)161 BASE_EXPORT ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfObjects(
162 JNIEnv* env,
163 base::span<const ScopedJavaGlobalRef<jobject>> v) {
164 jobjectArray joa = env->NewObjectArray(checked_cast<jsize>(v.size()),
165 jni_zero::g_object_class, nullptr);
166 CheckException(env);
167
168 for (size_t i = 0; i < v.size(); ++i) {
169 env->SetObjectArrayElement(joa, checked_cast<jsize>(i), v[i].obj());
170 }
171 return ScopedJavaLocalRef<jobjectArray>(env, joa);
172 }
173
ToTypedJavaArrayOfObjects(JNIEnv * env,base::span<const ScopedJavaLocalRef<jobject>> v,jclass type)174 BASE_EXPORT ScopedJavaLocalRef<jobjectArray> ToTypedJavaArrayOfObjects(
175 JNIEnv* env,
176 base::span<const ScopedJavaLocalRef<jobject>> v,
177 jclass type) {
178 jobjectArray joa =
179 env->NewObjectArray(checked_cast<jsize>(v.size()), type, nullptr);
180 CheckException(env);
181
182 for (size_t i = 0; i < v.size(); ++i) {
183 env->SetObjectArrayElement(joa, checked_cast<jsize>(i), v[i].obj());
184 }
185 return ScopedJavaLocalRef<jobjectArray>(env, joa);
186 }
187
ToTypedJavaArrayOfObjects(JNIEnv * env,base::span<const ScopedJavaGlobalRef<jobject>> v,jclass type)188 BASE_EXPORT ScopedJavaLocalRef<jobjectArray> ToTypedJavaArrayOfObjects(
189 JNIEnv* env,
190 base::span<const ScopedJavaGlobalRef<jobject>> v,
191 jclass type) {
192 jobjectArray joa =
193 env->NewObjectArray(checked_cast<jsize>(v.size()), type, nullptr);
194 CheckException(env);
195
196 for (size_t i = 0; i < v.size(); ++i) {
197 env->SetObjectArrayElement(joa, checked_cast<jsize>(i), v[i].obj());
198 }
199 return ScopedJavaLocalRef<jobjectArray>(env, joa);
200 }
201
ToJavaArrayOfByteArray(JNIEnv * env,base::span<const std::string> v)202 ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfByteArray(
203 JNIEnv* env,
204 base::span<const std::string> v) {
205 ScopedJavaLocalRef<jclass> byte_array_clazz = GetClass(env, "[B");
206 jobjectArray joa = env->NewObjectArray(checked_cast<jsize>(v.size()),
207 byte_array_clazz.obj(), nullptr);
208 CheckException(env);
209
210 for (size_t i = 0; i < v.size(); ++i) {
211 ScopedJavaLocalRef<jbyteArray> byte_array = ToJavaByteArray(env, v[i]);
212 env->SetObjectArrayElement(joa, checked_cast<jsize>(i), byte_array.obj());
213 }
214 return ScopedJavaLocalRef<jobjectArray>(env, joa);
215 }
216
ToJavaArrayOfByteArray(JNIEnv * env,base::span<const std::vector<uint8_t>> v)217 ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfByteArray(
218 JNIEnv* env,
219 base::span<const std::vector<uint8_t>> v) {
220 ScopedJavaLocalRef<jclass> byte_array_clazz = GetClass(env, "[B");
221 jobjectArray joa = env->NewObjectArray(checked_cast<jsize>(v.size()),
222 byte_array_clazz.obj(), nullptr);
223 CheckException(env);
224
225 for (size_t i = 0; i < v.size(); ++i) {
226 ScopedJavaLocalRef<jbyteArray> byte_array = ToJavaByteArray(env, v[i]);
227 env->SetObjectArrayElement(joa, checked_cast<jsize>(i), byte_array.obj());
228 }
229 return ScopedJavaLocalRef<jobjectArray>(env, joa);
230 }
231
ToJavaArrayOfStrings(JNIEnv * env,base::span<const std::string> v)232 ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfStrings(
233 JNIEnv* env,
234 base::span<const std::string> v) {
235 jobjectArray joa = env->NewObjectArray(checked_cast<jsize>(v.size()),
236 jni_zero::g_string_class, nullptr);
237 CheckException(env);
238
239 for (size_t i = 0; i < v.size(); ++i) {
240 ScopedJavaLocalRef<jstring> item = ConvertUTF8ToJavaString(env, v[i]);
241 env->SetObjectArrayElement(joa, checked_cast<jsize>(i), item.obj());
242 }
243 return ScopedJavaLocalRef<jobjectArray>(env, joa);
244 }
245
ToJavaArrayOfStringArray(JNIEnv * env,base::span<const std::vector<std::string>> vec_outer)246 ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfStringArray(
247 JNIEnv* env,
248 base::span<const std::vector<std::string>> vec_outer) {
249 ScopedJavaLocalRef<jclass> string_array_clazz =
250 GetClass(env, "[Ljava/lang/String;");
251
252 jobjectArray joa = env->NewObjectArray(checked_cast<jsize>(vec_outer.size()),
253 string_array_clazz.obj(), nullptr);
254 CheckException(env);
255
256 for (size_t i = 0; i < vec_outer.size(); ++i) {
257 ScopedJavaLocalRef<jobjectArray> inner =
258 ToJavaArrayOfStrings(env, vec_outer[i]);
259 env->SetObjectArrayElement(joa, checked_cast<jsize>(i), inner.obj());
260 }
261
262 return ScopedJavaLocalRef<jobjectArray>(env, joa);
263 }
264
ToJavaArrayOfStringArray(JNIEnv * env,base::span<const std::vector<std::u16string>> vec_outer)265 ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfStringArray(
266 JNIEnv* env,
267 base::span<const std::vector<std::u16string>> vec_outer) {
268 ScopedJavaLocalRef<jclass> string_array_clazz =
269 GetClass(env, "[Ljava/lang/String;");
270
271 jobjectArray joa = env->NewObjectArray(checked_cast<jsize>(vec_outer.size()),
272 string_array_clazz.obj(), nullptr);
273 CheckException(env);
274
275 for (size_t i = 0; i < vec_outer.size(); ++i) {
276 ScopedJavaLocalRef<jobjectArray> inner =
277 ToJavaArrayOfStrings(env, vec_outer[i]);
278 env->SetObjectArrayElement(joa, checked_cast<jsize>(i), inner.obj());
279 }
280
281 return ScopedJavaLocalRef<jobjectArray>(env, joa);
282 }
283
ToJavaArrayOfStrings(JNIEnv * env,base::span<const std::u16string> v)284 ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfStrings(
285 JNIEnv* env,
286 base::span<const std::u16string> v) {
287 jobjectArray joa = env->NewObjectArray(checked_cast<jsize>(v.size()),
288 jni_zero::g_string_class, nullptr);
289 CheckException(env);
290
291 for (size_t i = 0; i < v.size(); ++i) {
292 ScopedJavaLocalRef<jstring> item = ConvertUTF16ToJavaString(env, v[i]);
293 env->SetObjectArrayElement(joa, checked_cast<jsize>(i), item.obj());
294 }
295 return ScopedJavaLocalRef<jobjectArray>(env, joa);
296 }
297
AppendJavaStringArrayToStringVector(JNIEnv * env,const JavaRef<jobjectArray> & array,std::vector<std::u16string> * out)298 void AppendJavaStringArrayToStringVector(JNIEnv* env,
299 const JavaRef<jobjectArray>& array,
300 std::vector<std::u16string>* out) {
301 DCHECK(out);
302 if (!array)
303 return;
304 size_t len = SafeGetArrayLength(env, array);
305 if (!len) {
306 return;
307 }
308 out->resize(out->size() + len);
309 span<std::u16string> back = span(*out).last(len);
310 for (size_t i = 0; i < len; ++i) {
311 ScopedJavaLocalRef<jstring> str(
312 env, static_cast<jstring>(env->GetObjectArrayElement(
313 array.obj(), checked_cast<jsize>(i))));
314 ConvertJavaStringToUTF16(env, str.obj(), &back[i]);
315 }
316 }
317
AppendJavaStringArrayToStringVector(JNIEnv * env,const JavaRef<jobjectArray> & array,std::vector<std::string> * out)318 void AppendJavaStringArrayToStringVector(JNIEnv* env,
319 const JavaRef<jobjectArray>& array,
320 std::vector<std::string>* out) {
321 DCHECK(out);
322 if (!array)
323 return;
324 size_t len = SafeGetArrayLength(env, array);
325 if (!len) {
326 return;
327 }
328 out->resize(out->size() + len);
329 span<std::string> back = span(*out).last(len);
330 for (size_t i = 0; i < len; ++i) {
331 ScopedJavaLocalRef<jstring> str(
332 env, static_cast<jstring>(env->GetObjectArrayElement(
333 array.obj(), checked_cast<jsize>(i))));
334 ConvertJavaStringToUTF8(env, str.obj(), &back[i]);
335 }
336 }
337
AppendJavaByteArrayToByteVector(JNIEnv * env,const JavaRef<jbyteArray> & byte_array,std::vector<uint8_t> * out)338 void AppendJavaByteArrayToByteVector(JNIEnv* env,
339 const JavaRef<jbyteArray>& byte_array,
340 std::vector<uint8_t>* out) {
341 DCHECK(out);
342 if (!byte_array)
343 return;
344 size_t len = SafeGetArrayLength(env, byte_array);
345 if (!len) {
346 return;
347 }
348 out->resize(out->size() + len);
349 span<uint8_t> back = span(*out).last(len);
350
351 static_assert(sizeof(jbyte) == sizeof(uint8_t));
352 static_assert(alignof(jbyte) <= alignof(uint8_t));
353 env->GetByteArrayRegion(byte_array.obj(), jsize{0},
354 checked_cast<jsize>(back.size()),
355 reinterpret_cast<jbyte*>(back.data()));
356 }
357
JavaByteArrayToByteVector(JNIEnv * env,const JavaRef<jbyteArray> & byte_array,std::vector<uint8_t> * out)358 void JavaByteArrayToByteVector(JNIEnv* env,
359 const JavaRef<jbyteArray>& byte_array,
360 std::vector<uint8_t>* out) {
361 DCHECK(out);
362 DCHECK(byte_array);
363 out->clear();
364 AppendJavaByteArrayToByteVector(env, byte_array, out);
365 }
366
JavaByteArrayToByteSpan(JNIEnv * env,const JavaRef<jbyteArray> & byte_array,base::span<uint8_t> dest)367 size_t JavaByteArrayToByteSpan(JNIEnv* env,
368 const JavaRef<jbyteArray>& byte_array,
369 base::span<uint8_t> dest) {
370 CHECK(byte_array);
371 size_t len = SafeGetArrayLength(env, byte_array);
372 span<uint8_t> copy_dest = dest.first(len);
373
374 static_assert(sizeof(jbyte) == sizeof(uint8_t));
375 static_assert(alignof(jbyte) <= alignof(uint8_t));
376 env->GetByteArrayRegion(byte_array.obj(), jsize{0},
377 checked_cast<jsize>(copy_dest.size()),
378 reinterpret_cast<jbyte*>(copy_dest.data()));
379 return len;
380 }
381
JavaByteArrayToString(JNIEnv * env,const JavaRef<jbyteArray> & byte_array,std::string * out)382 void JavaByteArrayToString(JNIEnv* env,
383 const JavaRef<jbyteArray>& byte_array,
384 std::string* out) {
385 DCHECK(out);
386 DCHECK(byte_array);
387
388 std::vector<uint8_t> byte_vector;
389 JavaByteArrayToByteVector(env, byte_array, &byte_vector);
390 out->assign(byte_vector.begin(), byte_vector.end());
391 }
392
JavaBooleanArrayToBoolVector(JNIEnv * env,const JavaRef<jbooleanArray> & boolean_array,std::vector<bool> * out)393 void JavaBooleanArrayToBoolVector(JNIEnv* env,
394 const JavaRef<jbooleanArray>& boolean_array,
395 std::vector<bool>* out) {
396 DCHECK(out);
397 if (!boolean_array)
398 return;
399 size_t len = SafeGetArrayLength(env, boolean_array);
400 out->resize(len);
401 if (!len) {
402 return;
403 }
404 // SAFETY: `SafeGetArrayLength()` returns the number of elements in the
405 // `boolean_array`, though it can return 0 if the array is invalid. So we only
406 // call `GetBooleanArrayElements()` when it's positive. Then
407 // GetBooleanArrayElements() returns a buffer of the size returned from
408 // `SafeGetArrayLength()`.
409 span<jboolean> values = UNSAFE_BUFFERS(
410 span(env->GetBooleanArrayElements(boolean_array.obj(), nullptr), len));
411 for (size_t i = 0; i < values.size(); ++i) {
412 (*out)[i] = static_cast<bool>(values[i]);
413 }
414 env->ReleaseBooleanArrayElements(boolean_array.obj(), values.data(),
415 JNI_ABORT);
416 }
417
JavaIntArrayToIntVector(JNIEnv * env,const JavaRef<jintArray> & int_array,std::vector<int> * out)418 void JavaIntArrayToIntVector(JNIEnv* env,
419 const JavaRef<jintArray>& int_array,
420 std::vector<int>* out) {
421 DCHECK(out);
422 size_t len = SafeGetArrayLength(env, int_array);
423 out->resize(len);
424 if (!len)
425 return;
426 env->GetIntArrayRegion(int_array.obj(), jsize{0}, checked_cast<jsize>(len),
427 out->data());
428 }
429
JavaLongArrayToInt64Vector(JNIEnv * env,const JavaRef<jlongArray> & long_array,std::vector<int64_t> * out)430 void JavaLongArrayToInt64Vector(JNIEnv* env,
431 const JavaRef<jlongArray>& long_array,
432 std::vector<int64_t>* out) {
433 DCHECK(out);
434 std::vector<jlong> temp;
435 JavaLongArrayToLongVector(env, long_array, &temp);
436 out->resize(0);
437 Extend(*out, temp);
438 }
439
JavaLongArrayToLongVector(JNIEnv * env,const JavaRef<jlongArray> & long_array,std::vector<jlong> * out)440 void JavaLongArrayToLongVector(JNIEnv* env,
441 const JavaRef<jlongArray>& long_array,
442 std::vector<jlong>* out) {
443 DCHECK(out);
444 size_t len = SafeGetArrayLength(env, long_array);
445 out->resize(len);
446 if (!len)
447 return;
448 env->GetLongArrayRegion(long_array.obj(), jsize{0}, checked_cast<jsize>(len),
449 out->data());
450 }
451
JavaFloatArrayToFloatVector(JNIEnv * env,const JavaRef<jfloatArray> & float_array,std::vector<float> * out)452 void JavaFloatArrayToFloatVector(JNIEnv* env,
453 const JavaRef<jfloatArray>& float_array,
454 std::vector<float>* out) {
455 DCHECK(out);
456 size_t len = SafeGetArrayLength(env, float_array);
457 out->resize(len);
458 if (!len)
459 return;
460 env->GetFloatArrayRegion(float_array.obj(), jsize{0},
461 checked_cast<jsize>(len), out->data());
462 }
463
JavaDoubleArrayToDoubleVector(JNIEnv * env,const JavaRef<jdoubleArray> & double_array,std::vector<double> * out)464 void JavaDoubleArrayToDoubleVector(JNIEnv* env,
465 const JavaRef<jdoubleArray>& double_array,
466 std::vector<double>* out) {
467 DCHECK(out);
468 size_t len = SafeGetArrayLength(env, double_array);
469 out->resize(len);
470 if (!len)
471 return;
472 env->GetDoubleArrayRegion(double_array.obj(), jsize{0},
473 checked_cast<jsize>(len), out->data());
474 }
475
JavaArrayOfByteArrayToStringVector(JNIEnv * env,const JavaRef<jobjectArray> & array,std::vector<std::string> * out)476 void JavaArrayOfByteArrayToStringVector(JNIEnv* env,
477 const JavaRef<jobjectArray>& array,
478 std::vector<std::string>* out) {
479 DCHECK(out);
480 size_t len = SafeGetArrayLength(env, array);
481 out->resize(len);
482 for (size_t i = 0; i < len; ++i) {
483 ScopedJavaLocalRef<jbyteArray> bytes_array(
484 env, static_cast<jbyteArray>(env->GetObjectArrayElement(
485 array.obj(), checked_cast<jsize>(i))));
486 size_t bytes_len = SafeGetArrayLength(env, bytes_array);
487 // SAFETY: `SafeGetArrayLength()` returns the number of elements in the
488 // `boobytes_array`, though it can return 0 if the array is invalid. So we
489 // only call `GetByteArrayElements()` when it's positive. Then
490 // GetByteArrayElements() returns a buffer of the size returned from
491 // `SafeGetArrayLength()`.
492 if (!bytes_len) {
493 (*out)[i].clear();
494 continue;
495 }
496 span<jbyte> bytes = UNSAFE_BUFFERS(
497 span(env->GetByteArrayElements(bytes_array.obj(), nullptr), bytes_len));
498 (*out)[i] = base::as_string_view(base::as_bytes(bytes));
499 env->ReleaseByteArrayElements(bytes_array.obj(), bytes.data(), JNI_ABORT);
500 }
501 }
502
JavaArrayOfByteArrayToBytesVector(JNIEnv * env,const JavaRef<jobjectArray> & array,std::vector<std::vector<uint8_t>> * out)503 void JavaArrayOfByteArrayToBytesVector(JNIEnv* env,
504 const JavaRef<jobjectArray>& array,
505 std::vector<std::vector<uint8_t>>* out) {
506 DCHECK(out);
507 const size_t len = SafeGetArrayLength(env, array);
508 out->resize(len);
509 for (size_t i = 0; i < len; ++i) {
510 ScopedJavaLocalRef<jbyteArray> bytes_array(
511 env, static_cast<jbyteArray>(env->GetObjectArrayElement(
512 array.obj(), checked_cast<jsize>(i))));
513 JavaByteArrayToByteVector(env, bytes_array, &(*out)[i]);
514 }
515 }
516
Java2dStringArrayTo2dStringVector(JNIEnv * env,const JavaRef<jobjectArray> & array,std::vector<std::vector<std::u16string>> * out)517 void Java2dStringArrayTo2dStringVector(
518 JNIEnv* env,
519 const JavaRef<jobjectArray>& array,
520 std::vector<std::vector<std::u16string>>* out) {
521 DCHECK(out);
522 size_t len = SafeGetArrayLength(env, array);
523 out->resize(len);
524 for (size_t i = 0; i < len; ++i) {
525 ScopedJavaLocalRef<jobjectArray> strings_array(
526 env, static_cast<jobjectArray>(env->GetObjectArrayElement(
527 array.obj(), checked_cast<jsize>(i))));
528
529 (*out)[i].clear();
530 AppendJavaStringArrayToStringVector(env, strings_array, &(*out)[i]);
531 }
532 }
533
Java2dStringArrayTo2dStringVector(JNIEnv * env,const JavaRef<jobjectArray> & array,std::vector<std::vector<std::string>> * out)534 void Java2dStringArrayTo2dStringVector(
535 JNIEnv* env,
536 const JavaRef<jobjectArray>& array,
537 std::vector<std::vector<std::string>>* out) {
538 DCHECK(out);
539 size_t len = SafeGetArrayLength(env, array);
540 out->resize(len);
541 for (size_t i = 0; i < len; ++i) {
542 ScopedJavaLocalRef<jobjectArray> strings_array(
543 env, static_cast<jobjectArray>(env->GetObjectArrayElement(
544 array.obj(), checked_cast<jsize>(i))));
545
546 (*out)[i].clear();
547 AppendJavaStringArrayToStringVector(env, strings_array, &(*out)[i]);
548 }
549 }
550
JavaArrayOfIntArrayToIntVector(JNIEnv * env,const JavaRef<jobjectArray> & array,std::vector<std::vector<int>> * out)551 void JavaArrayOfIntArrayToIntVector(JNIEnv* env,
552 const JavaRef<jobjectArray>& array,
553 std::vector<std::vector<int>>* out) {
554 DCHECK(out);
555 size_t len = SafeGetArrayLength(env, array);
556 out->resize(len);
557 for (size_t i = 0; i < len; ++i) {
558 ScopedJavaLocalRef<jintArray> int_array(
559 env, static_cast<jintArray>(env->GetObjectArrayElement(
560 array.obj(), checked_cast<jsize>(i))));
561 JavaIntArrayToIntVector(env, int_array, &(*out)[i]);
562 }
563 }
564
565 } // namespace base::android
566