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
35using android::AndroidRuntime;
36
37using ::android::hardware::hidl_string;
38using ::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
44namespace android {
45
46static struct fields_t {
47    jfieldID contextID;
48    jmethodID constructID;
49
50} gFields;
51
52void 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
131void 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
142sp<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
160sp<JHwParcel> JHwParcel::GetNativeContext(JNIEnv *env, jobject thiz) {
161    return (JHwParcel *)env->GetLongField(thiz, gFields.contextID);
162}
163
164JHwParcel::JHwParcel(JNIEnv *env, jobject thiz)
165    : mParcel(NULL),
166      mOwnsParcel(false),
167      mTransactCallback(nullptr),
168      mWasSent(false) {
169}
170
171JHwParcel::~JHwParcel() {
172    JNIEnv *env = AndroidRuntime::getJNIEnv();
173
174    mStorage.release(env);
175
176    setParcel(NULL, false /* assumeOwnership */);
177}
178
179hardware::Parcel *JHwParcel::getParcel() {
180    return mParcel;
181}
182
183EphemeralStorage *JHwParcel::getStorage() {
184    return &mStorage;
185}
186
187void 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
197jobject 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
206void JHwParcel::setTransactCallback(
207        ::android::hardware::IBinder::TransactCallback cb) {
208    mTransactCallback = cb;
209}
210
211void JHwParcel::send() {
212    CHECK(mTransactCallback != nullptr);
213    CHECK(mParcel != nullptr);
214
215    mTransactCallback(*mParcel);
216    mTransactCallback = nullptr;
217
218    mWasSent = true;
219}
220
221bool JHwParcel::wasSent() const {
222    return mWasSent;
223}
224
225}  // namespace android
226
227////////////////////////////////////////////////////////////////////////////////
228
229using namespace android;
230
231static void releaseNativeContext(void *nativeContext) {
232    sp<JHwParcel> parcel = (JHwParcel *)nativeContext;
233
234    if (parcel != NULL) {
235        parcel->decStrong(NULL /* id */);
236    }
237}
238
239static jlong JHwParcel_native_init(JNIEnv *env) {
240    JHwParcel::InitClass(env);
241
242    return reinterpret_cast<jlong>(&releaseNativeContext);
243}
244
245static 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
256static 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
280static 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)                               \
314static 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)                               \
324static 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
336DEFINE_PARCEL_WRITER(Bool,jboolean)
337DEFINE_PARCEL_WRITER(Int8,jbyte)
338DEFINE_PARCEL_WRITER(Int16,jshort)
339DEFINE_PARCEL_WRITER(Int32,jint)
340DEFINE_PARCEL_WRITER(Int64,jlong)
341DEFINE_PARCEL_WRITER(Float,jfloat)
342DEFINE_PARCEL_WRITER(Double,jdouble)
343
344DEFINE_PARCEL_READER(Int8,jbyte)
345DEFINE_PARCEL_READER(Int16,jshort)
346DEFINE_PARCEL_READER(Int32,jint)
347DEFINE_PARCEL_READER(Int64,jlong)
348DEFINE_PARCEL_READER(Float,jfloat)
349DEFINE_PARCEL_READER(Double,jdouble)
350
351static 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
362static 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
385static 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
400static void JHwParcel_native_release(
401        JNIEnv *env, jobject thiz) {
402    JHwParcel::GetNativeContext(env, thiz)->setParcel(NULL, false /* assumeOwnership */);
403}
404
405static void JHwParcel_native_releaseTemporaryStorage(
406        JNIEnv *env, jobject thiz) {
407    JHwParcel::GetNativeContext(env, thiz)->getStorage()->release(env);
408}
409
410static void JHwParcel_native_send(JNIEnv *env, jobject thiz) {
411    JHwParcel::GetNativeContext(env, thiz)->send();
412}
413
414static 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)                               \
440static 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
471DEFINE_PARCEL_VECTOR_WRITER(Int8,jbyte)
472DEFINE_PARCEL_VECTOR_WRITER(Int16,jshort)
473DEFINE_PARCEL_VECTOR_WRITER(Int32,jint)
474DEFINE_PARCEL_VECTOR_WRITER(Int64,jlong)
475DEFINE_PARCEL_VECTOR_WRITER(Float,jfloat)
476DEFINE_PARCEL_VECTOR_WRITER(Double,jdouble)
477
478static 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
527static 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
555static 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
563static 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)                       \
591static 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
626DEFINE_PARCEL_VECTOR_READER(Int8,jbyte,Byte)
627DEFINE_PARCEL_VECTOR_READER(Int16,jshort,Short)
628DEFINE_PARCEL_VECTOR_READER(Int32,jint,Int)
629DEFINE_PARCEL_VECTOR_READER(Int64,jlong,Long)
630DEFINE_PARCEL_VECTOR_READER(Float,jfloat,Float)
631DEFINE_PARCEL_VECTOR_READER(Double,jdouble,Double)
632
633static 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
673static 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
695static 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
734static 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
792static 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
805static 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
828static 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
857static 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
875static 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
973namespace android {
974
975int register_android_os_HwParcel(JNIEnv *env) {
976    return RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods));
977}
978
979}  // namespace android
980