1 /*
2 * Copyright (C) 2016 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 //#define LOG_NDEBUG 0
18 #define LOG_TAG "android_os_HwParcel"
19 #include <android-base/logging.h>
20
21 #include "android_os_HwParcel.h"
22
23 #include "android_os_HwBinder.h"
24 #include "android_os_HwBlob.h"
25 #include "android_os_HwRemoteBinder.h"
26
27 #include <nativehelper/JNIHelp.h>
28 #include <android_runtime/AndroidRuntime.h>
29 #include <hidl/HidlTransportSupport.h>
30 #include <hidl/Status.h>
31 #include <nativehelper/ScopedLocalRef.h>
32
33 #include "core_jni_helpers.h"
34
35 using android::AndroidRuntime;
36
37 using ::android::hardware::hidl_string;
38 using ::android::hardware::hidl_vec;
39
40 #define PACKAGE_PATH "android/os"
41 #define CLASS_NAME "HwParcel"
42 #define CLASS_PATH PACKAGE_PATH "/" CLASS_NAME
43
44 namespace android {
45
46 static struct fields_t {
47 jfieldID contextID;
48 jmethodID constructID;
49
50 } gFields;
51
signalExceptionForError(JNIEnv * env,status_t err,bool canThrowRemoteException)52 void signalExceptionForError(JNIEnv *env, status_t err, bool canThrowRemoteException) {
53 switch (err) {
54 case OK:
55 break;
56
57 case NO_MEMORY:
58 {
59 jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
60 break;
61 }
62
63 case INVALID_OPERATION:
64 {
65 jniThrowException(
66 env, "java/lang/UnsupportedOperationException", NULL);
67 break;
68 }
69
70 case BAD_VALUE:
71 {
72 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
73 break;
74 }
75
76 case -ERANGE:
77 case BAD_INDEX:
78 {
79 jniThrowException(env, "java/lang/IndexOutOfBoundsException", NULL);
80 break;
81 }
82
83 case BAD_TYPE:
84 {
85 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
86 break;
87 }
88
89 case NAME_NOT_FOUND:
90 {
91 jniThrowException(env, "java/util/NoSuchElementException", NULL);
92 break;
93 }
94
95 case PERMISSION_DENIED:
96 {
97 jniThrowException(env, "java/lang/SecurityException", NULL);
98 break;
99 }
100
101 case NO_INIT:
102 {
103 jniThrowException(
104 env, "java/lang/RuntimeException", "Not initialized");
105 break;
106 }
107
108 case ALREADY_EXISTS:
109 {
110 jniThrowException(
111 env, "java/lang/RuntimeException", "Item already exists");
112 break;
113 }
114
115 default:
116 {
117 std::stringstream ss;
118 ss << "HwBinder Error: (" << err << ")";
119
120 jniThrowException(
121 env,
122 canThrowRemoteException ? "android/os/RemoteException" : "java/lang/RuntimeException",
123 ss.str().c_str());
124
125 break;
126 }
127 }
128 }
129
130 // static
InitClass(JNIEnv * env)131 void JHwParcel::InitClass(JNIEnv *env) {
132 ScopedLocalRef<jclass> clazz(
133 env, FindClassOrDie(env, CLASS_PATH));
134
135 gFields.contextID =
136 GetFieldIDOrDie(env, clazz.get(), "mNativeContext", "J");
137
138 gFields.constructID = GetMethodIDOrDie(env, clazz.get(), "<init>", "(Z)V");
139 }
140
141 // static
SetNativeContext(JNIEnv * env,jobject thiz,const sp<JHwParcel> & context)142 sp<JHwParcel> JHwParcel::SetNativeContext(
143 JNIEnv *env, jobject thiz, const sp<JHwParcel> &context) {
144 sp<JHwParcel> old = (JHwParcel *)env->GetLongField(thiz, gFields.contextID);
145
146 if (context != NULL) {
147 context->incStrong(NULL /* id */);
148 }
149
150 if (old != NULL) {
151 old->decStrong(NULL /* id */);
152 }
153
154 env->SetLongField(thiz, gFields.contextID, (long)context.get());
155
156 return old;
157 }
158
159 // static
GetNativeContext(JNIEnv * env,jobject thiz)160 sp<JHwParcel> JHwParcel::GetNativeContext(JNIEnv *env, jobject thiz) {
161 return (JHwParcel *)env->GetLongField(thiz, gFields.contextID);
162 }
163
JHwParcel(JNIEnv * env,jobject thiz)164 JHwParcel::JHwParcel(JNIEnv *env, jobject thiz)
165 : mParcel(NULL),
166 mOwnsParcel(false),
167 mTransactCallback(nullptr),
168 mWasSent(false) {
169 }
170
~JHwParcel()171 JHwParcel::~JHwParcel() {
172 JNIEnv *env = AndroidRuntime::getJNIEnv();
173
174 mStorage.release(env);
175
176 setParcel(NULL, false /* assumeOwnership */);
177 }
178
getParcel()179 hardware::Parcel *JHwParcel::getParcel() {
180 return mParcel;
181 }
182
getStorage()183 EphemeralStorage *JHwParcel::getStorage() {
184 return &mStorage;
185 }
186
setParcel(hardware::Parcel * parcel,bool assumeOwnership)187 void JHwParcel::setParcel(hardware::Parcel *parcel, bool assumeOwnership) {
188 if (mParcel && mOwnsParcel) {
189 delete mParcel;
190 }
191
192 mParcel = parcel;
193 mOwnsParcel = assumeOwnership;
194 }
195
196 // static
NewObject(JNIEnv * env)197 jobject JHwParcel::NewObject(JNIEnv *env) {
198 ScopedLocalRef<jclass> clazz(env, FindClassOrDie(env, CLASS_PATH));
199
200 jmethodID constructID =
201 GetMethodIDOrDie(env, clazz.get(), "<init>", "(Z)V");
202
203 return env->NewObject(clazz.get(), constructID, false /* allocate */);
204 }
205
setTransactCallback(::android::hardware::IBinder::TransactCallback cb)206 void JHwParcel::setTransactCallback(
207 ::android::hardware::IBinder::TransactCallback cb) {
208 mTransactCallback = cb;
209 }
210
send()211 void JHwParcel::send() {
212 CHECK(mTransactCallback != nullptr);
213 CHECK(mParcel != nullptr);
214
215 mTransactCallback(*mParcel);
216 mTransactCallback = nullptr;
217
218 mWasSent = true;
219 }
220
wasSent() const221 bool JHwParcel::wasSent() const {
222 return mWasSent;
223 }
224
225 } // namespace android
226
227 ////////////////////////////////////////////////////////////////////////////////
228
229 using namespace android;
230
releaseNativeContext(void * nativeContext)231 static void releaseNativeContext(void *nativeContext) {
232 sp<JHwParcel> parcel = (JHwParcel *)nativeContext;
233
234 if (parcel != NULL) {
235 parcel->decStrong(NULL /* id */);
236 }
237 }
238
JHwParcel_native_init(JNIEnv * env)239 static jlong JHwParcel_native_init(JNIEnv *env) {
240 JHwParcel::InitClass(env);
241
242 return reinterpret_cast<jlong>(&releaseNativeContext);
243 }
244
JHwParcel_native_setup(JNIEnv * env,jobject thiz,jboolean allocate)245 static void JHwParcel_native_setup(
246 JNIEnv *env, jobject thiz, jboolean allocate) {
247 sp<JHwParcel> context = new JHwParcel(env, thiz);
248
249 if (allocate) {
250 context->setParcel(new hardware::Parcel, true /* assumeOwnership */);
251 }
252
253 JHwParcel::SetNativeContext(env, thiz, context);
254 }
255
JHwParcel_native_writeInterfaceToken(JNIEnv * env,jobject thiz,jstring interfaceNameObj)256 static void JHwParcel_native_writeInterfaceToken(
257 JNIEnv *env, jobject thiz, jstring interfaceNameObj) {
258 if (interfaceNameObj == NULL) {
259 jniThrowException(env, "java/lang/NullPointerException", NULL);
260 return;
261 }
262
263 const jchar *interfaceName = env->GetStringCritical(interfaceNameObj, NULL);
264 if (interfaceName) {
265 String8 nameCopy = String8(String16(
266 reinterpret_cast<const char16_t *>(interfaceName),
267 env->GetStringLength(interfaceNameObj)));
268
269 env->ReleaseStringCritical(interfaceNameObj, interfaceName);
270 interfaceName = NULL;
271
272 hardware::Parcel *parcel =
273 JHwParcel::GetNativeContext(env, thiz)->getParcel();
274
275 status_t err = parcel->writeInterfaceToken(nameCopy.string());
276 signalExceptionForError(env, err);
277 }
278 }
279
JHwParcel_native_enforceInterface(JNIEnv * env,jobject thiz,jstring interfaceNameObj)280 static void JHwParcel_native_enforceInterface(
281 JNIEnv *env, jobject thiz, jstring interfaceNameObj) {
282 // XXX original binder Parcel enforceInterface implementation does some
283 // mysterious things regarding strictModePolicy(), figure out if we need
284 // that here as well.
285 if (interfaceNameObj == NULL) {
286 jniThrowException(env, "java/lang/NullPointerException", NULL);
287 return;
288 }
289
290 const jchar *interfaceName = env->GetStringCritical(interfaceNameObj, NULL);
291 if (interfaceName) {
292 String8 interfaceNameCopy = String8(String16(
293 reinterpret_cast<const char16_t *>(interfaceName),
294 env->GetStringLength(interfaceNameObj)));
295
296 env->ReleaseStringCritical(interfaceNameObj, interfaceName);
297 interfaceName = NULL;
298
299 hardware::Parcel *parcel =
300 JHwParcel::GetNativeContext(env, thiz)->getParcel();
301
302 bool valid = parcel->enforceInterface(interfaceNameCopy.string());
303
304 if (!valid) {
305 jniThrowException(
306 env,
307 "java/lang/SecurityException",
308 "HWBinder invocation to an incorrect interface");
309 }
310 }
311 }
312
313 #define DEFINE_PARCEL_WRITER(Suffix,Type) \
314 static void JHwParcel_native_write ## Suffix( \
315 JNIEnv *env, jobject thiz, Type val) { \
316 hardware::Parcel *parcel = \
317 JHwParcel::GetNativeContext(env, thiz)->getParcel(); \
318 \
319 status_t err = parcel->write ## Suffix(val); \
320 signalExceptionForError(env, err); \
321 }
322
323 #define DEFINE_PARCEL_READER(Suffix,Type) \
324 static Type JHwParcel_native_read ## Suffix( \
325 JNIEnv *env, jobject thiz) { \
326 hardware::Parcel *parcel = \
327 JHwParcel::GetNativeContext(env, thiz)->getParcel(); \
328 \
329 Type val; \
330 status_t err = parcel->read ## Suffix(&val); \
331 signalExceptionForError(env, err); \
332 \
333 return val; \
334 }
335
DEFINE_PARCEL_WRITER(Bool,jboolean)336 DEFINE_PARCEL_WRITER(Bool,jboolean)
337 DEFINE_PARCEL_WRITER(Int8,jbyte)
338 DEFINE_PARCEL_WRITER(Int16,jshort)
339 DEFINE_PARCEL_WRITER(Int32,jint)
340 DEFINE_PARCEL_WRITER(Int64,jlong)
341 DEFINE_PARCEL_WRITER(Float,jfloat)
342 DEFINE_PARCEL_WRITER(Double,jdouble)
343
344 DEFINE_PARCEL_READER(Int8,jbyte)
345 DEFINE_PARCEL_READER(Int16,jshort)
346 DEFINE_PARCEL_READER(Int32,jint)
347 DEFINE_PARCEL_READER(Int64,jlong)
348 DEFINE_PARCEL_READER(Float,jfloat)
349 DEFINE_PARCEL_READER(Double,jdouble)
350
351 static jboolean JHwParcel_native_readBool(JNIEnv *env, jobject thiz) {
352 hardware::Parcel *parcel =
353 JHwParcel::GetNativeContext(env, thiz)->getParcel();
354
355 bool val;
356 status_t err = parcel->readBool(&val);
357 signalExceptionForError(env, err);
358
359 return (jboolean)val;
360 }
361
JHwParcel_native_writeStatus(JNIEnv * env,jobject thiz,jint statusCode)362 static void JHwParcel_native_writeStatus(
363 JNIEnv *env, jobject thiz, jint statusCode) {
364 using hardware::Status;
365
366 Status status;
367 switch (statusCode) {
368 case 0: // kStatusSuccess
369 status = Status::ok();
370 break;
371 case -1: // kStatusError
372 status = Status::fromStatusT(UNKNOWN_ERROR);
373 break;
374 default:
375 CHECK(!"Should not be here");
376 }
377
378 hardware::Parcel *parcel =
379 JHwParcel::GetNativeContext(env, thiz)->getParcel();
380
381 status_t err = ::android::hardware::writeToParcel(status, parcel);
382 signalExceptionForError(env, err);
383 }
384
JHwParcel_native_verifySuccess(JNIEnv * env,jobject thiz)385 static void JHwParcel_native_verifySuccess(JNIEnv *env, jobject thiz) {
386 using hardware::Status;
387
388 hardware::Parcel *parcel =
389 JHwParcel::GetNativeContext(env, thiz)->getParcel();
390
391 Status status;
392 status_t err = ::android::hardware::readFromParcel(&status, *parcel);
393 signalExceptionForError(env, err);
394 }
395
JHwParcel_native_release(JNIEnv * env,jobject thiz)396 static void JHwParcel_native_release(
397 JNIEnv *env, jobject thiz) {
398 JHwParcel::GetNativeContext(env, thiz)->setParcel(NULL, false /* assumeOwnership */);
399 }
400
JHwParcel_native_releaseTemporaryStorage(JNIEnv * env,jobject thiz)401 static void JHwParcel_native_releaseTemporaryStorage(
402 JNIEnv *env, jobject thiz) {
403 JHwParcel::GetNativeContext(env, thiz)->getStorage()->release(env);
404 }
405
JHwParcel_native_send(JNIEnv * env,jobject thiz)406 static void JHwParcel_native_send(JNIEnv *env, jobject thiz) {
407 JHwParcel::GetNativeContext(env, thiz)->send();
408 }
409
JHwParcel_native_writeString(JNIEnv * env,jobject thiz,jstring valObj)410 static void JHwParcel_native_writeString(
411 JNIEnv *env, jobject thiz, jstring valObj) {
412 if (valObj == NULL) {
413 jniThrowException(env, "java/lang/NullPointerException", NULL);
414 return;
415 }
416
417 sp<JHwParcel> impl = JHwParcel::GetNativeContext(env, thiz);
418
419 const hidl_string *s =
420 impl->getStorage()->allocTemporaryString(env, valObj);
421
422 hardware::Parcel *parcel = impl->getParcel();
423
424 size_t parentHandle;
425 status_t err = parcel->writeBuffer(s, sizeof(*s), &parentHandle);
426
427 if (err == OK) {
428 err = ::android::hardware::writeEmbeddedToParcel(
429 *s, parcel, parentHandle, 0 /* parentOffset */);
430 }
431
432 signalExceptionForError(env, err);
433 }
434
435 #define DEFINE_PARCEL_VECTOR_WRITER(Suffix,Type) \
436 static void JHwParcel_native_write ## Suffix ## Vector( \
437 JNIEnv *env, jobject thiz, Type ## Array valObj) { \
438 if (valObj == NULL) { \
439 jniThrowException(env, "java/lang/NullPointerException", NULL); \
440 return; \
441 } \
442 \
443 sp<JHwParcel> impl = JHwParcel::GetNativeContext(env, thiz); \
444 \
445 const hidl_vec<Type> *vec = \
446 impl->getStorage()->allocTemporary ## Suffix ## Vector(env, valObj); \
447 \
448 hardware::Parcel *parcel = impl->getParcel(); \
449 \
450 size_t parentHandle; \
451 status_t err = parcel->writeBuffer(vec, sizeof(*vec), &parentHandle); \
452 \
453 if (err == OK) { \
454 size_t childHandle; \
455 \
456 err = ::android::hardware::writeEmbeddedToParcel( \
457 *vec, \
458 parcel, \
459 parentHandle, \
460 0 /* parentOffset */, \
461 &childHandle); \
462 } \
463 \
464 signalExceptionForError(env, err); \
465 }
466
DEFINE_PARCEL_VECTOR_WRITER(Int8,jbyte)467 DEFINE_PARCEL_VECTOR_WRITER(Int8,jbyte)
468 DEFINE_PARCEL_VECTOR_WRITER(Int16,jshort)
469 DEFINE_PARCEL_VECTOR_WRITER(Int32,jint)
470 DEFINE_PARCEL_VECTOR_WRITER(Int64,jlong)
471 DEFINE_PARCEL_VECTOR_WRITER(Float,jfloat)
472 DEFINE_PARCEL_VECTOR_WRITER(Double,jdouble)
473
474 static void JHwParcel_native_writeBoolVector(
475 JNIEnv *env, jobject thiz, jbooleanArray valObj) {
476 if (valObj == NULL) {
477 jniThrowException(env, "java/lang/NullPointerException", NULL);
478 return;
479 }
480
481 sp<JHwParcel> impl = JHwParcel::GetNativeContext(env, thiz);
482
483 void *vecPtr =
484 impl->getStorage()->allocTemporaryStorage(sizeof(hidl_vec<bool>));
485
486 hidl_vec<bool> *vec = new (vecPtr) hidl_vec<bool>;
487
488 jsize len = env->GetArrayLength(valObj);
489
490 jboolean *src = env->GetBooleanArrayElements(valObj, nullptr);
491
492 bool *dst =
493 (bool *)impl->getStorage()->allocTemporaryStorage(len * sizeof(bool));
494
495 for (jsize i = 0; i < len; ++i) {
496 dst[i] = src[i];
497 }
498
499 env->ReleaseBooleanArrayElements(valObj, src, 0 /* mode */);
500 src = nullptr;
501
502 vec->setToExternal(dst, len);
503
504 hardware::Parcel *parcel = impl->getParcel();
505
506 size_t parentHandle;
507 status_t err = parcel->writeBuffer(vec, sizeof(*vec), &parentHandle);
508
509 if (err == OK) {
510 size_t childHandle;
511
512 err = ::android::hardware::writeEmbeddedToParcel(
513 *vec,
514 parcel,
515 parentHandle,
516 0 /* parentOffset */,
517 &childHandle);
518 }
519
520 signalExceptionForError(env, err);
521 }
522
JHwParcel_native_writeStrongBinder(JNIEnv * env,jobject thiz,jobject binderObj)523 static void JHwParcel_native_writeStrongBinder(
524 JNIEnv *env, jobject thiz, jobject binderObj) {
525 sp<hardware::IBinder> binder;
526 if (binderObj != NULL) {
527 ScopedLocalRef<jclass> hwBinderKlass(
528 env, FindClassOrDie(env, PACKAGE_PATH "/HwBinder"));
529
530 ScopedLocalRef<jclass> hwRemoteBinderKlass(
531 env, FindClassOrDie(env, PACKAGE_PATH "/HwRemoteBinder"));
532
533 if (env->IsInstanceOf(binderObj, hwBinderKlass.get())) {
534 binder = JHwBinder::GetNativeBinder(env, binderObj);
535 } else if (env->IsInstanceOf(binderObj, hwRemoteBinderKlass.get())) {
536 binder = JHwRemoteBinder::GetNativeContext(
537 env, binderObj)->getBinder();
538 } else {
539 signalExceptionForError(env, INVALID_OPERATION);
540 return;
541 }
542 }
543
544 hardware::Parcel *parcel =
545 JHwParcel::GetNativeContext(env, thiz)->getParcel();
546
547 status_t err = parcel->writeStrongBinder(binder);
548 signalExceptionForError(env, err);
549 }
550
MakeStringObjFromHidlString(JNIEnv * env,const hidl_string & s)551 static jstring MakeStringObjFromHidlString(JNIEnv *env, const hidl_string &s) {
552 String16 utf16String(s.c_str(), s.size());
553
554 return env->NewString(
555 reinterpret_cast<const jchar *>(utf16String.string()),
556 utf16String.size());
557 }
558
JHwParcel_native_readString(JNIEnv * env,jobject thiz)559 static jstring JHwParcel_native_readString(JNIEnv *env, jobject thiz) {
560 hardware::Parcel *parcel =
561 JHwParcel::GetNativeContext(env, thiz)->getParcel();
562
563 size_t parentHandle;
564
565 const hidl_string *s;
566 status_t err = parcel->readBuffer(sizeof(*s), &parentHandle,
567 reinterpret_cast<const void**>(&s));
568
569 if (err != OK) {
570 signalExceptionForError(env, err);
571 return NULL;
572 }
573
574 err = ::android::hardware::readEmbeddedFromParcel(
575 const_cast<hidl_string &>(*s),
576 *parcel, parentHandle, 0 /* parentOffset */);
577
578 if (err != OK) {
579 signalExceptionForError(env, err);
580 return NULL;
581 }
582
583 return MakeStringObjFromHidlString(env, *s);
584 }
585
586 #define DEFINE_PARCEL_VECTOR_READER(Suffix,Type,NewType) \
587 static Type ## Array JHwParcel_native_read ## Suffix ## Vector( \
588 JNIEnv *env, jobject thiz) { \
589 hardware::Parcel *parcel = \
590 JHwParcel::GetNativeContext(env, thiz)->getParcel(); \
591 size_t parentHandle; \
592 \
593 const hidl_vec<Type> *vec; \
594 status_t err = parcel->readBuffer(sizeof(*vec), &parentHandle, \
595 reinterpret_cast<const void**>(&vec)); \
596 \
597 if (err != OK) { \
598 signalExceptionForError(env, err); \
599 return NULL; \
600 } \
601 \
602 size_t childHandle; \
603 \
604 err = ::android::hardware::readEmbeddedFromParcel( \
605 const_cast<hidl_vec<Type> &>(*vec), \
606 *parcel, \
607 parentHandle, \
608 0 /* parentOffset */, \
609 &childHandle); \
610 \
611 if (err != OK) { \
612 signalExceptionForError(env, err); \
613 return NULL; \
614 } \
615 \
616 Type ## Array valObj = env->New ## NewType ## Array(vec->size()); \
617 env->Set ## NewType ## ArrayRegion(valObj, 0, vec->size(), &(*vec)[0]); \
618 \
619 return valObj; \
620 }
621
DEFINE_PARCEL_VECTOR_READER(Int8,jbyte,Byte)622 DEFINE_PARCEL_VECTOR_READER(Int8,jbyte,Byte)
623 DEFINE_PARCEL_VECTOR_READER(Int16,jshort,Short)
624 DEFINE_PARCEL_VECTOR_READER(Int32,jint,Int)
625 DEFINE_PARCEL_VECTOR_READER(Int64,jlong,Long)
626 DEFINE_PARCEL_VECTOR_READER(Float,jfloat,Float)
627 DEFINE_PARCEL_VECTOR_READER(Double,jdouble,Double)
628
629 static jbooleanArray JHwParcel_native_readBoolVector(
630 JNIEnv *env, jobject thiz) {
631 hardware::Parcel *parcel =
632 JHwParcel::GetNativeContext(env, thiz)->getParcel();
633
634 size_t parentHandle;
635
636 const hidl_vec<bool> *vec;
637 status_t err = parcel->readBuffer(sizeof(*vec), &parentHandle,
638 reinterpret_cast<const void**>(&vec));
639
640 if (err != OK) {
641 signalExceptionForError(env, err);
642 return NULL;
643 }
644
645 size_t childHandle;
646
647 err = ::android::hardware::readEmbeddedFromParcel(
648 const_cast<hidl_vec<bool> &>(*vec),
649 *parcel,
650 parentHandle,
651 0 /* parentOffset */,
652 &childHandle);
653
654 if (err != OK) {
655 signalExceptionForError(env, err);
656 return NULL;
657 }
658
659 jbooleanArray valObj = env->NewBooleanArray(vec->size());
660
661 for (size_t i = 0; i < vec->size(); ++i) {
662 jboolean x = (*vec)[i];
663 env->SetBooleanArrayRegion(valObj, i, 1, &x);
664 }
665
666 return valObj;
667 }
668
MakeStringArray(JNIEnv * env,const hidl_string * array,size_t size)669 static jobjectArray MakeStringArray(
670 JNIEnv *env, const hidl_string *array, size_t size) {
671 ScopedLocalRef<jclass> stringKlass(
672 env,
673 env->FindClass("java/lang/String"));
674
675 // XXX Why can't I use ScopedLocalRef<> for the arrayObj and the stringObjs?
676
677 jobjectArray arrayObj = env->NewObjectArray(size, stringKlass.get(), NULL);
678
679 for (size_t i = 0; i < size; ++i) {
680 jstring stringObj = MakeStringObjFromHidlString(env, array[i]);
681
682 env->SetObjectArrayElement(
683 arrayObj,
684 i,
685 stringObj);
686 }
687
688 return arrayObj;
689 }
690
JHwParcel_native_readStringVector(JNIEnv * env,jobject thiz)691 static jobjectArray JHwParcel_native_readStringVector(
692 JNIEnv *env, jobject thiz) {
693 typedef hidl_vec<hidl_string> string_vec;
694
695 hardware::Parcel *parcel =
696 JHwParcel::GetNativeContext(env, thiz)->getParcel();
697
698 size_t parentHandle;
699
700 const string_vec *vec;
701 status_t err = parcel->readBuffer(sizeof(*vec), &parentHandle,
702 reinterpret_cast<const void **>(&vec));
703
704 if (err != OK) {
705 signalExceptionForError(env, err);
706 return NULL;
707 }
708
709 size_t childHandle;
710 err = ::android::hardware::readEmbeddedFromParcel(
711 const_cast<string_vec &>(*vec),
712 *parcel, parentHandle, 0 /* parentOffset */, &childHandle);
713
714 for (size_t i = 0; (err == OK) && (i < vec->size()); ++i) {
715 err = android::hardware::readEmbeddedFromParcel(
716 const_cast<hidl_string &>((*vec)[i]),
717 *parcel,
718 childHandle,
719 i * sizeof(hidl_string) /* parentOffset */);
720 }
721
722 if (err != OK) {
723 signalExceptionForError(env, err);
724 return NULL;
725 }
726
727 return MakeStringArray(env, &(*vec)[0], vec->size());
728 }
729
JHwParcel_native_writeStringVector(JNIEnv * env,jobject thiz,jobjectArray arrayObj)730 static void JHwParcel_native_writeStringVector(
731 JNIEnv *env, jobject thiz, jobjectArray arrayObj) {
732 typedef hidl_vec<hidl_string> string_vec;
733
734 if (arrayObj == NULL) {
735 jniThrowException(env, "java/lang/NullPointerException", NULL);
736 return;
737 }
738
739 jsize len = env->GetArrayLength(arrayObj);
740
741 sp<JHwParcel> impl = JHwParcel::GetNativeContext(env, thiz);
742
743 void *vecPtr =
744 impl->getStorage()->allocTemporaryStorage(sizeof(string_vec));
745
746 string_vec *vec = new (vecPtr) string_vec;
747
748 hidl_string *strings = impl->getStorage()->allocStringArray(len);
749 vec->setToExternal(strings, len);
750
751 for (jsize i = 0; i < len; ++i) {
752 ScopedLocalRef<jstring> stringObj(
753 env,
754 (jstring)env->GetObjectArrayElement(arrayObj, i));
755
756 const hidl_string *s =
757 impl->getStorage()->allocTemporaryString(env, stringObj.get());
758
759 strings[i].setToExternal(s->c_str(), s->size());
760 }
761
762 hardware::Parcel *parcel = impl->getParcel();
763
764 size_t parentHandle;
765 status_t err = parcel->writeBuffer(vec, sizeof(*vec), &parentHandle);
766
767 if (err == OK) {
768 size_t childHandle;
769 err = ::android::hardware::writeEmbeddedToParcel(
770 *vec,
771 parcel,
772 parentHandle,
773 0 /* parentOffset */,
774 &childHandle);
775
776 for (size_t i = 0; (err == OK) && (i < vec->size()); ++i) {
777 err = ::android::hardware::writeEmbeddedToParcel(
778 (*vec)[i],
779 parcel,
780 childHandle,
781 i * sizeof(hidl_string));
782 }
783 }
784
785 signalExceptionForError(env, err);
786 }
787
JHwParcel_native_readStrongBinder(JNIEnv * env,jobject thiz)788 static jobject JHwParcel_native_readStrongBinder(JNIEnv *env, jobject thiz) {
789 hardware::Parcel *parcel =
790 JHwParcel::GetNativeContext(env, thiz)->getParcel();
791
792 sp<hardware::IBinder> binder = parcel->readStrongBinder();
793
794 if (binder == NULL) {
795 return NULL;
796 }
797
798 return JHwRemoteBinder::NewObject(env, binder);
799 }
800
JHwParcel_native_readBuffer(JNIEnv * env,jobject thiz,jlong expectedSize)801 static jobject JHwParcel_native_readBuffer(JNIEnv *env, jobject thiz,
802 jlong expectedSize) {
803 hardware::Parcel *parcel =
804 JHwParcel::GetNativeContext(env, thiz)->getParcel();
805
806 size_t handle;
807 const void *ptr;
808
809 if (expectedSize < 0) {
810 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
811 return nullptr;
812 }
813
814 status_t status = parcel->readBuffer(expectedSize, &handle, &ptr);
815
816 if (status != OK) {
817 jniThrowException(env, "java/util/NoSuchElementException", NULL);
818 return nullptr;
819 }
820
821 return JHwBlob::NewObject(env, ptr, handle);
822 }
823
JHwParcel_native_readEmbeddedBuffer(JNIEnv * env,jobject thiz,jlong expectedSize,jlong parentHandle,jlong offset,jboolean nullable)824 static jobject JHwParcel_native_readEmbeddedBuffer(
825 JNIEnv *env, jobject thiz, jlong expectedSize,
826 jlong parentHandle, jlong offset, jboolean nullable) {
827 hardware::Parcel *parcel =
828 JHwParcel::GetNativeContext(env, thiz)->getParcel();
829
830 size_t childHandle;
831
832 const void *ptr;
833 status_t status =
834 parcel->readNullableEmbeddedBuffer(expectedSize,
835 &childHandle, parentHandle, offset, &ptr);
836
837 if (expectedSize < 0) {
838 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
839 return nullptr;
840 }
841
842 if (status != OK) {
843 jniThrowException(env, "java/util/NoSuchElementException", NULL);
844 return 0;
845 } else if (status == OK && !nullable && ptr == nullptr) {
846 jniThrowException(env, "java/lang/NullPointerException", NULL);
847 return 0;
848 }
849
850 return JHwBlob::NewObject(env, ptr, childHandle);
851 }
852
JHwParcel_native_writeBuffer(JNIEnv * env,jobject thiz,jobject blobObj)853 static void JHwParcel_native_writeBuffer(
854 JNIEnv *env, jobject thiz, jobject blobObj) {
855 if (blobObj == nullptr) {
856 jniThrowException(env, "java/lang/NullPointerException", NULL);
857 return;
858 }
859
860 hardware::Parcel *parcel =
861 JHwParcel::GetNativeContext(env, thiz)->getParcel();
862
863 sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, blobObj);
864 status_t err = blob->writeToParcel(parcel);
865
866 if (err != OK) {
867 signalExceptionForError(env, err);
868 }
869 }
870
871 static JNINativeMethod gMethods[] = {
872 { "native_init", "()J", (void *)JHwParcel_native_init },
873 { "native_setup", "(Z)V", (void *)JHwParcel_native_setup },
874
875 { "writeInterfaceToken", "(Ljava/lang/String;)V",
876 (void *)JHwParcel_native_writeInterfaceToken },
877
878 { "writeBool", "(Z)V", (void *)JHwParcel_native_writeBool },
879 { "writeInt8", "(B)V", (void *)JHwParcel_native_writeInt8 },
880 { "writeInt16", "(S)V", (void *)JHwParcel_native_writeInt16 },
881 { "writeInt32", "(I)V", (void *)JHwParcel_native_writeInt32 },
882 { "writeInt64", "(J)V", (void *)JHwParcel_native_writeInt64 },
883 { "writeFloat", "(F)V", (void *)JHwParcel_native_writeFloat },
884 { "writeDouble", "(D)V", (void *)JHwParcel_native_writeDouble },
885
886 { "writeString", "(Ljava/lang/String;)V",
887 (void *)JHwParcel_native_writeString },
888
889 { "writeBoolVector", "([Z)V", (void *)JHwParcel_native_writeBoolVector },
890 { "writeInt8Vector", "([B)V", (void *)JHwParcel_native_writeInt8Vector },
891 { "writeInt16Vector", "([S)V", (void *)JHwParcel_native_writeInt16Vector },
892 { "writeInt32Vector", "([I)V", (void *)JHwParcel_native_writeInt32Vector },
893 { "writeInt64Vector", "([J)V", (void *)JHwParcel_native_writeInt64Vector },
894 { "writeFloatVector", "([F)V", (void *)JHwParcel_native_writeFloatVector },
895
896 { "writeDoubleVector", "([D)V",
897 (void *)JHwParcel_native_writeDoubleVector },
898
899 { "writeStringVector", "([Ljava/lang/String;)V",
900 (void *)JHwParcel_native_writeStringVector },
901
902 { "writeStrongBinder", "(L" PACKAGE_PATH "/IHwBinder;)V",
903 (void *)JHwParcel_native_writeStrongBinder },
904
905 { "enforceInterface", "(Ljava/lang/String;)V",
906 (void *)JHwParcel_native_enforceInterface },
907
908 { "readBool", "()Z", (void *)JHwParcel_native_readBool },
909 { "readInt8", "()B", (void *)JHwParcel_native_readInt8 },
910 { "readInt16", "()S", (void *)JHwParcel_native_readInt16 },
911 { "readInt32", "()I", (void *)JHwParcel_native_readInt32 },
912 { "readInt64", "()J", (void *)JHwParcel_native_readInt64 },
913 { "readFloat", "()F", (void *)JHwParcel_native_readFloat },
914 { "readDouble", "()D", (void *)JHwParcel_native_readDouble },
915
916 { "readString", "()Ljava/lang/String;",
917 (void *)JHwParcel_native_readString },
918
919 { "readBoolVectorAsArray", "()[Z",
920 (void *)JHwParcel_native_readBoolVector },
921
922 { "readInt8VectorAsArray", "()[B",
923 (void *)JHwParcel_native_readInt8Vector },
924
925 { "readInt16VectorAsArray", "()[S",
926 (void *)JHwParcel_native_readInt16Vector },
927
928 { "readInt32VectorAsArray", "()[I",
929 (void *)JHwParcel_native_readInt32Vector },
930
931 { "readInt64VectorAsArray", "()[J",
932 (void *)JHwParcel_native_readInt64Vector },
933
934 { "readFloatVectorAsArray", "()[F",
935 (void *)JHwParcel_native_readFloatVector },
936
937 { "readDoubleVectorAsArray", "()[D",
938 (void *)JHwParcel_native_readDoubleVector },
939
940 { "readStringVectorAsArray", "()[Ljava/lang/String;",
941 (void *)JHwParcel_native_readStringVector },
942
943 { "readStrongBinder", "()L" PACKAGE_PATH "/IHwBinder;",
944 (void *)JHwParcel_native_readStrongBinder },
945
946 { "writeStatus", "(I)V", (void *)JHwParcel_native_writeStatus },
947
948 { "verifySuccess", "()V", (void *)JHwParcel_native_verifySuccess },
949
950 { "releaseTemporaryStorage", "()V",
951 (void *)JHwParcel_native_releaseTemporaryStorage },
952
953 { "send", "()V", (void *)JHwParcel_native_send },
954
955 { "readBuffer", "(J)L" PACKAGE_PATH "/HwBlob;",
956 (void *)JHwParcel_native_readBuffer },
957
958 { "readEmbeddedBuffer", "(JJJZ)L" PACKAGE_PATH "/HwBlob;",
959 (void *)JHwParcel_native_readEmbeddedBuffer },
960
961 { "writeBuffer", "(L" PACKAGE_PATH "/HwBlob;)V",
962 (void *)JHwParcel_native_writeBuffer },
963
964 { "release", "()V",
965 (void *)JHwParcel_native_release },
966
967 };
968
969 namespace android {
970
register_android_os_HwParcel(JNIEnv * env)971 int register_android_os_HwParcel(JNIEnv *env) {
972 return RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods));
973 }
974
975 } // namespace android
976