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     if (!status.isOk()) {
396         signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
397     }
398 }
399 
JHwParcel_native_release(JNIEnv * env,jobject thiz)400 static void JHwParcel_native_release(
401         JNIEnv *env, jobject thiz) {
402     JHwParcel::GetNativeContext(env, thiz)->setParcel(NULL, false /* assumeOwnership */);
403 }
404 
JHwParcel_native_releaseTemporaryStorage(JNIEnv * env,jobject thiz)405 static void JHwParcel_native_releaseTemporaryStorage(
406         JNIEnv *env, jobject thiz) {
407     JHwParcel::GetNativeContext(env, thiz)->getStorage()->release(env);
408 }
409 
JHwParcel_native_send(JNIEnv * env,jobject thiz)410 static void JHwParcel_native_send(JNIEnv *env, jobject thiz) {
411     JHwParcel::GetNativeContext(env, thiz)->send();
412 }
413 
JHwParcel_native_writeString(JNIEnv * env,jobject thiz,jstring valObj)414 static void JHwParcel_native_writeString(
415         JNIEnv *env, jobject thiz, jstring valObj) {
416     if (valObj == NULL) {
417         jniThrowException(env, "java/lang/NullPointerException", NULL);
418         return;
419     }
420 
421     sp<JHwParcel> impl = JHwParcel::GetNativeContext(env, thiz);
422 
423     const hidl_string *s =
424         impl->getStorage()->allocTemporaryString(env, valObj);
425 
426     hardware::Parcel *parcel = impl->getParcel();
427 
428     size_t parentHandle;
429     status_t err = parcel->writeBuffer(s, sizeof(*s), &parentHandle);
430 
431     if (err == OK) {
432         err = ::android::hardware::writeEmbeddedToParcel(
433                 *s, parcel, parentHandle, 0 /* parentOffset */);
434     }
435 
436     signalExceptionForError(env, err);
437 }
438 
439 #define DEFINE_PARCEL_VECTOR_WRITER(Suffix,Type)                               \
440 static void JHwParcel_native_write ## Suffix ## Vector(                        \
441         JNIEnv *env, jobject thiz, Type ## Array valObj) {                     \
442     if (valObj == NULL) {                                                      \
443         jniThrowException(env, "java/lang/NullPointerException", NULL);        \
444         return;                                                                \
445     }                                                                          \
446                                                                                \
447     sp<JHwParcel> impl = JHwParcel::GetNativeContext(env, thiz);               \
448                                                                                \
449     const hidl_vec<Type> *vec =                                                \
450         impl->getStorage()->allocTemporary ## Suffix ## Vector(env, valObj);   \
451                                                                                \
452     hardware::Parcel *parcel = impl->getParcel();                              \
453                                                                                \
454     size_t parentHandle;                                                       \
455     status_t err = parcel->writeBuffer(vec, sizeof(*vec), &parentHandle);      \
456                                                                                \
457     if (err == OK) {                                                           \
458         size_t childHandle;                                                    \
459                                                                                \
460         err = ::android::hardware::writeEmbeddedToParcel(                      \
461                 *vec,                                                          \
462                 parcel,                                                        \
463                 parentHandle,                                                  \
464                 0 /* parentOffset */,                                          \
465                 &childHandle);                                                 \
466     }                                                                          \
467                                                                                \
468     signalExceptionForError(env, err);                                         \
469 }
470 
DEFINE_PARCEL_VECTOR_WRITER(Int8,jbyte)471 DEFINE_PARCEL_VECTOR_WRITER(Int8,jbyte)
472 DEFINE_PARCEL_VECTOR_WRITER(Int16,jshort)
473 DEFINE_PARCEL_VECTOR_WRITER(Int32,jint)
474 DEFINE_PARCEL_VECTOR_WRITER(Int64,jlong)
475 DEFINE_PARCEL_VECTOR_WRITER(Float,jfloat)
476 DEFINE_PARCEL_VECTOR_WRITER(Double,jdouble)
477 
478 static void JHwParcel_native_writeBoolVector(
479         JNIEnv *env, jobject thiz, jbooleanArray valObj) {
480     if (valObj == NULL) {
481         jniThrowException(env, "java/lang/NullPointerException", NULL);
482         return;
483     }
484 
485     sp<JHwParcel> impl = JHwParcel::GetNativeContext(env, thiz);
486 
487     void *vecPtr =
488         impl->getStorage()->allocTemporaryStorage(sizeof(hidl_vec<bool>));
489 
490     hidl_vec<bool> *vec = new (vecPtr) hidl_vec<bool>;
491 
492     jsize len = env->GetArrayLength(valObj);
493 
494     jboolean *src = env->GetBooleanArrayElements(valObj, nullptr);
495 
496     bool *dst =
497         (bool *)impl->getStorage()->allocTemporaryStorage(len * sizeof(bool));
498 
499     for (jsize i = 0; i < len; ++i) {
500         dst[i] = src[i];
501     }
502 
503     env->ReleaseBooleanArrayElements(valObj, src, 0 /* mode */);
504     src = nullptr;
505 
506     vec->setToExternal(dst, len);
507 
508     hardware::Parcel *parcel = impl->getParcel();
509 
510     size_t parentHandle;
511     status_t err = parcel->writeBuffer(vec, sizeof(*vec), &parentHandle);
512 
513     if (err == OK) {
514         size_t childHandle;
515 
516         err = ::android::hardware::writeEmbeddedToParcel(
517                 *vec,
518                 parcel,
519                 parentHandle,
520                 0 /* parentOffset */,
521                 &childHandle);
522     }
523 
524     signalExceptionForError(env, err);
525 }
526 
JHwParcel_native_writeStrongBinder(JNIEnv * env,jobject thiz,jobject binderObj)527 static void JHwParcel_native_writeStrongBinder(
528         JNIEnv *env, jobject thiz, jobject binderObj) {
529     sp<hardware::IBinder> binder;
530     if (binderObj != NULL) {
531         ScopedLocalRef<jclass> hwBinderKlass(
532                 env, FindClassOrDie(env, PACKAGE_PATH "/HwBinder"));
533 
534         ScopedLocalRef<jclass> hwRemoteBinderKlass(
535                 env, FindClassOrDie(env, PACKAGE_PATH "/HwRemoteBinder"));
536 
537         if (env->IsInstanceOf(binderObj, hwBinderKlass.get())) {
538             binder = JHwBinder::GetNativeBinder(env, binderObj);
539         } else if (env->IsInstanceOf(binderObj, hwRemoteBinderKlass.get())) {
540             binder = JHwRemoteBinder::GetNativeContext(
541                     env, binderObj)->getBinder();
542         } else {
543             signalExceptionForError(env, INVALID_OPERATION);
544             return;
545         }
546     }
547 
548     hardware::Parcel *parcel =
549         JHwParcel::GetNativeContext(env, thiz)->getParcel();
550 
551     status_t err = parcel->writeStrongBinder(binder);
552     signalExceptionForError(env, err);
553 }
554 
MakeStringObjFromHidlString(JNIEnv * env,const hidl_string & s)555 static jstring MakeStringObjFromHidlString(JNIEnv *env, const hidl_string &s) {
556     String16 utf16String(s.c_str(), s.size());
557 
558     return env->NewString(
559             reinterpret_cast<const jchar *>(utf16String.string()),
560             utf16String.size());
561 }
562 
JHwParcel_native_readString(JNIEnv * env,jobject thiz)563 static jstring JHwParcel_native_readString(JNIEnv *env, jobject thiz) {
564     hardware::Parcel *parcel =
565         JHwParcel::GetNativeContext(env, thiz)->getParcel();
566 
567     size_t parentHandle;
568 
569     const hidl_string *s;
570     status_t err = parcel->readBuffer(sizeof(*s), &parentHandle,
571             reinterpret_cast<const void**>(&s));
572 
573     if (err != OK) {
574         signalExceptionForError(env, err);
575         return NULL;
576     }
577 
578     err = ::android::hardware::readEmbeddedFromParcel(
579             const_cast<hidl_string &>(*s),
580             *parcel, parentHandle, 0 /* parentOffset */);
581 
582     if (err != OK) {
583         signalExceptionForError(env, err);
584         return NULL;
585     }
586 
587     return MakeStringObjFromHidlString(env, *s);
588 }
589 
590 #define DEFINE_PARCEL_VECTOR_READER(Suffix,Type,NewType)                       \
591 static Type ## Array JHwParcel_native_read ## Suffix ## Vector(                \
592         JNIEnv *env, jobject thiz) {                                           \
593     hardware::Parcel *parcel =                                                 \
594         JHwParcel::GetNativeContext(env, thiz)->getParcel();                   \
595     size_t parentHandle;                                                       \
596                                                                                \
597     const hidl_vec<Type> *vec;                                                 \
598     status_t err = parcel->readBuffer(sizeof(*vec), &parentHandle,             \
599             reinterpret_cast<const void**>(&vec));                             \
600                                                                                \
601     if (err != OK) {                                                           \
602         signalExceptionForError(env, err);                                     \
603         return NULL;                                                           \
604     }                                                                          \
605                                                                                \
606     size_t childHandle;                                                        \
607                                                                                \
608     err = ::android::hardware::readEmbeddedFromParcel(                         \
609                 const_cast<hidl_vec<Type> &>(*vec),                            \
610                 *parcel,                                                       \
611                 parentHandle,                                                  \
612                 0 /* parentOffset */,                                          \
613                 &childHandle);                                                 \
614                                                                                \
615     if (err != OK) {                                                           \
616         signalExceptionForError(env, err);                                     \
617         return NULL;                                                           \
618     }                                                                          \
619                                                                                \
620     Type ## Array valObj = env->New ## NewType ## Array(vec->size());          \
621     env->Set ## NewType ## ArrayRegion(valObj, 0, vec->size(), &(*vec)[0]);    \
622                                                                                \
623     return valObj;                                                             \
624 }
625 
DEFINE_PARCEL_VECTOR_READER(Int8,jbyte,Byte)626 DEFINE_PARCEL_VECTOR_READER(Int8,jbyte,Byte)
627 DEFINE_PARCEL_VECTOR_READER(Int16,jshort,Short)
628 DEFINE_PARCEL_VECTOR_READER(Int32,jint,Int)
629 DEFINE_PARCEL_VECTOR_READER(Int64,jlong,Long)
630 DEFINE_PARCEL_VECTOR_READER(Float,jfloat,Float)
631 DEFINE_PARCEL_VECTOR_READER(Double,jdouble,Double)
632 
633 static jbooleanArray JHwParcel_native_readBoolVector(
634         JNIEnv *env, jobject thiz) {
635     hardware::Parcel *parcel =
636         JHwParcel::GetNativeContext(env, thiz)->getParcel();
637 
638     size_t parentHandle;
639 
640     const hidl_vec<bool> *vec;
641     status_t err = parcel->readBuffer(sizeof(*vec), &parentHandle,
642             reinterpret_cast<const void**>(&vec));
643 
644     if (err != OK) {
645         signalExceptionForError(env, err);
646         return NULL;
647     }
648 
649     size_t childHandle;
650 
651     err = ::android::hardware::readEmbeddedFromParcel(
652                 const_cast<hidl_vec<bool> &>(*vec),
653                 *parcel,
654                 parentHandle,
655                 0 /* parentOffset */,
656                 &childHandle);
657 
658     if (err != OK) {
659         signalExceptionForError(env, err);
660         return NULL;
661     }
662 
663     jbooleanArray valObj = env->NewBooleanArray(vec->size());
664 
665     for (size_t i = 0; i < vec->size(); ++i) {
666         jboolean x = (*vec)[i];
667         env->SetBooleanArrayRegion(valObj, i, 1, &x);
668     }
669 
670     return valObj;
671 }
672 
MakeStringArray(JNIEnv * env,const hidl_string * array,size_t size)673 static jobjectArray MakeStringArray(
674         JNIEnv *env, const hidl_string *array, size_t size) {
675     ScopedLocalRef<jclass> stringKlass(
676             env,
677             env->FindClass("java/lang/String"));
678 
679     // XXX Why can't I use ScopedLocalRef<> for the arrayObj and the stringObjs?
680 
681     jobjectArray arrayObj = env->NewObjectArray(size, stringKlass.get(), NULL);
682 
683     for (size_t i = 0; i < size; ++i) {
684         jstring stringObj = MakeStringObjFromHidlString(env, array[i]);
685 
686         env->SetObjectArrayElement(
687                 arrayObj,
688                 i,
689                 stringObj);
690     }
691 
692     return arrayObj;
693 }
694 
JHwParcel_native_readStringVector(JNIEnv * env,jobject thiz)695 static jobjectArray JHwParcel_native_readStringVector(
696         JNIEnv *env, jobject thiz) {
697     typedef hidl_vec<hidl_string> string_vec;
698 
699     hardware::Parcel *parcel =
700         JHwParcel::GetNativeContext(env, thiz)->getParcel();
701 
702     size_t parentHandle;
703 
704     const string_vec *vec;
705     status_t err = parcel->readBuffer(sizeof(*vec), &parentHandle,
706             reinterpret_cast<const void **>(&vec));
707 
708     if (err != OK) {
709         signalExceptionForError(env, err);
710         return NULL;
711     }
712 
713     size_t childHandle;
714     err = ::android::hardware::readEmbeddedFromParcel(
715             const_cast<string_vec &>(*vec),
716             *parcel, parentHandle, 0 /* parentOffset */, &childHandle);
717 
718     for (size_t i = 0; (err == OK) && (i < vec->size()); ++i) {
719         err = android::hardware::readEmbeddedFromParcel(
720                     const_cast<hidl_string &>((*vec)[i]),
721                     *parcel,
722                     childHandle,
723                     i * sizeof(hidl_string) /* parentOffset */);
724     }
725 
726     if (err != OK) {
727         signalExceptionForError(env, err);
728         return NULL;
729     }
730 
731     return MakeStringArray(env, &(*vec)[0], vec->size());
732 }
733 
JHwParcel_native_writeStringVector(JNIEnv * env,jobject thiz,jobjectArray arrayObj)734 static void JHwParcel_native_writeStringVector(
735         JNIEnv *env, jobject thiz, jobjectArray arrayObj) {
736     typedef hidl_vec<hidl_string> string_vec;
737 
738     if (arrayObj == NULL) {
739         jniThrowException(env, "java/lang/NullPointerException", NULL);
740         return;
741     }
742 
743     jsize len = env->GetArrayLength(arrayObj);
744 
745     sp<JHwParcel> impl = JHwParcel::GetNativeContext(env, thiz);
746 
747     void *vecPtr =
748         impl->getStorage()->allocTemporaryStorage(sizeof(string_vec));
749 
750     string_vec *vec = new (vecPtr) string_vec;
751 
752     hidl_string *strings = impl->getStorage()->allocStringArray(len);
753     vec->setToExternal(strings, len);
754 
755     for (jsize i = 0; i < len; ++i) {
756         ScopedLocalRef<jstring> stringObj(
757                 env,
758                 (jstring)env->GetObjectArrayElement(arrayObj, i));
759 
760         const hidl_string *s =
761             impl->getStorage()->allocTemporaryString(env, stringObj.get());
762 
763         strings[i].setToExternal(s->c_str(), s->size());
764     }
765 
766     hardware::Parcel *parcel = impl->getParcel();
767 
768     size_t parentHandle;
769     status_t err = parcel->writeBuffer(vec, sizeof(*vec), &parentHandle);
770 
771     if (err == OK) {
772         size_t childHandle;
773         err = ::android::hardware::writeEmbeddedToParcel(
774                 *vec,
775                 parcel,
776                 parentHandle,
777                 0 /* parentOffset */,
778                 &childHandle);
779 
780         for (size_t i = 0; (err == OK) && (i < vec->size()); ++i) {
781             err = ::android::hardware::writeEmbeddedToParcel(
782                     (*vec)[i],
783                     parcel,
784                     childHandle,
785                     i * sizeof(hidl_string));
786         }
787     }
788 
789     signalExceptionForError(env, err);
790 }
791 
JHwParcel_native_readStrongBinder(JNIEnv * env,jobject thiz)792 static jobject JHwParcel_native_readStrongBinder(JNIEnv *env, jobject thiz) {
793     hardware::Parcel *parcel =
794         JHwParcel::GetNativeContext(env, thiz)->getParcel();
795 
796     sp<hardware::IBinder> binder = parcel->readStrongBinder();
797 
798     if (binder == NULL) {
799         return NULL;
800     }
801 
802     return JHwRemoteBinder::NewObject(env, binder);
803 }
804 
JHwParcel_native_readBuffer(JNIEnv * env,jobject thiz,jlong expectedSize)805 static jobject JHwParcel_native_readBuffer(JNIEnv *env, jobject thiz,
806                                            jlong expectedSize) {
807     hardware::Parcel *parcel =
808         JHwParcel::GetNativeContext(env, thiz)->getParcel();
809 
810     size_t handle;
811     const void *ptr;
812 
813     if (expectedSize < 0) {
814         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
815         return nullptr;
816     }
817 
818     status_t status = parcel->readBuffer(expectedSize, &handle, &ptr);
819 
820     if (status != OK) {
821         jniThrowException(env, "java/util/NoSuchElementException", NULL);
822         return nullptr;
823     }
824 
825     return JHwBlob::NewObject(env, ptr, handle);
826 }
827 
JHwParcel_native_readEmbeddedBuffer(JNIEnv * env,jobject thiz,jlong expectedSize,jlong parentHandle,jlong offset,jboolean nullable)828 static jobject JHwParcel_native_readEmbeddedBuffer(
829         JNIEnv *env, jobject thiz, jlong expectedSize,
830         jlong parentHandle, jlong offset, jboolean nullable) {
831     hardware::Parcel *parcel =
832         JHwParcel::GetNativeContext(env, thiz)->getParcel();
833 
834     size_t childHandle;
835 
836     const void *ptr;
837     status_t status =
838         parcel->readNullableEmbeddedBuffer(expectedSize,
839                 &childHandle, parentHandle, offset, &ptr);
840 
841     if (expectedSize < 0) {
842         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
843         return nullptr;
844     }
845 
846     if (status != OK) {
847         jniThrowException(env, "java/util/NoSuchElementException", NULL);
848         return 0;
849     } else if (status == OK && !nullable && ptr == nullptr) {
850         jniThrowException(env, "java/lang/NullPointerException", NULL);
851         return 0;
852     }
853 
854     return JHwBlob::NewObject(env, ptr, childHandle);
855 }
856 
JHwParcel_native_writeBuffer(JNIEnv * env,jobject thiz,jobject blobObj)857 static void JHwParcel_native_writeBuffer(
858         JNIEnv *env, jobject thiz, jobject blobObj) {
859     if (blobObj == nullptr) {
860         jniThrowException(env, "java/lang/NullPointerException", NULL);
861         return;
862     }
863 
864     hardware::Parcel *parcel =
865         JHwParcel::GetNativeContext(env, thiz)->getParcel();
866 
867     sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, blobObj);
868     status_t err = blob->writeToParcel(parcel);
869 
870     if (err != OK) {
871         signalExceptionForError(env, err);
872     }
873 }
874 
875 static JNINativeMethod gMethods[] = {
876     { "native_init", "()J", (void *)JHwParcel_native_init },
877     { "native_setup", "(Z)V", (void *)JHwParcel_native_setup },
878 
879     { "writeInterfaceToken", "(Ljava/lang/String;)V",
880         (void *)JHwParcel_native_writeInterfaceToken },
881 
882     { "writeBool", "(Z)V", (void *)JHwParcel_native_writeBool },
883     { "writeInt8", "(B)V", (void *)JHwParcel_native_writeInt8 },
884     { "writeInt16", "(S)V", (void *)JHwParcel_native_writeInt16 },
885     { "writeInt32", "(I)V", (void *)JHwParcel_native_writeInt32 },
886     { "writeInt64", "(J)V", (void *)JHwParcel_native_writeInt64 },
887     { "writeFloat", "(F)V", (void *)JHwParcel_native_writeFloat },
888     { "writeDouble", "(D)V", (void *)JHwParcel_native_writeDouble },
889 
890     { "writeString", "(Ljava/lang/String;)V",
891         (void *)JHwParcel_native_writeString },
892 
893     { "writeBoolVector", "([Z)V", (void *)JHwParcel_native_writeBoolVector },
894     { "writeInt8Vector", "([B)V", (void *)JHwParcel_native_writeInt8Vector },
895     { "writeInt16Vector", "([S)V", (void *)JHwParcel_native_writeInt16Vector },
896     { "writeInt32Vector", "([I)V", (void *)JHwParcel_native_writeInt32Vector },
897     { "writeInt64Vector", "([J)V", (void *)JHwParcel_native_writeInt64Vector },
898     { "writeFloatVector", "([F)V", (void *)JHwParcel_native_writeFloatVector },
899 
900     { "writeDoubleVector", "([D)V",
901         (void *)JHwParcel_native_writeDoubleVector },
902 
903     { "writeStringVector", "([Ljava/lang/String;)V",
904         (void *)JHwParcel_native_writeStringVector },
905 
906     { "writeStrongBinder", "(L" PACKAGE_PATH "/IHwBinder;)V",
907         (void *)JHwParcel_native_writeStrongBinder },
908 
909     { "enforceInterface", "(Ljava/lang/String;)V",
910         (void *)JHwParcel_native_enforceInterface },
911 
912     { "readBool", "()Z", (void *)JHwParcel_native_readBool },
913     { "readInt8", "()B", (void *)JHwParcel_native_readInt8 },
914     { "readInt16", "()S", (void *)JHwParcel_native_readInt16 },
915     { "readInt32", "()I", (void *)JHwParcel_native_readInt32 },
916     { "readInt64", "()J", (void *)JHwParcel_native_readInt64 },
917     { "readFloat", "()F", (void *)JHwParcel_native_readFloat },
918     { "readDouble", "()D", (void *)JHwParcel_native_readDouble },
919 
920     { "readString", "()Ljava/lang/String;",
921         (void *)JHwParcel_native_readString },
922 
923     { "readBoolVectorAsArray", "()[Z",
924         (void *)JHwParcel_native_readBoolVector },
925 
926     { "readInt8VectorAsArray", "()[B",
927         (void *)JHwParcel_native_readInt8Vector },
928 
929     { "readInt16VectorAsArray", "()[S",
930         (void *)JHwParcel_native_readInt16Vector },
931 
932     { "readInt32VectorAsArray", "()[I",
933         (void *)JHwParcel_native_readInt32Vector },
934 
935     { "readInt64VectorAsArray", "()[J",
936         (void *)JHwParcel_native_readInt64Vector },
937 
938     { "readFloatVectorAsArray", "()[F",
939         (void *)JHwParcel_native_readFloatVector },
940 
941     { "readDoubleVectorAsArray", "()[D",
942         (void *)JHwParcel_native_readDoubleVector },
943 
944     { "readStringVectorAsArray", "()[Ljava/lang/String;",
945         (void *)JHwParcel_native_readStringVector },
946 
947     { "readStrongBinder", "()L" PACKAGE_PATH "/IHwBinder;",
948         (void *)JHwParcel_native_readStrongBinder },
949 
950     { "writeStatus", "(I)V", (void *)JHwParcel_native_writeStatus },
951 
952     { "verifySuccess", "()V", (void *)JHwParcel_native_verifySuccess },
953 
954     { "releaseTemporaryStorage", "()V",
955         (void *)JHwParcel_native_releaseTemporaryStorage },
956 
957     { "send", "()V", (void *)JHwParcel_native_send },
958 
959     { "readBuffer", "(J)L" PACKAGE_PATH "/HwBlob;",
960         (void *)JHwParcel_native_readBuffer },
961 
962     { "readEmbeddedBuffer", "(JJJZ)L" PACKAGE_PATH "/HwBlob;",
963         (void *)JHwParcel_native_readEmbeddedBuffer },
964 
965     { "writeBuffer", "(L" PACKAGE_PATH "/HwBlob;)V",
966         (void *)JHwParcel_native_writeBuffer },
967 
968     { "release", "()V",
969         (void *)JHwParcel_native_release },
970 
971 };
972 
973 namespace android {
974 
register_android_os_HwParcel(JNIEnv * env)975 int register_android_os_HwParcel(JNIEnv *env) {
976     return RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods));
977 }
978 
979 }  // namespace android
980