Adds framework support for hidl-gen Java backend. (to support structs) (DO NOT MERGE)

Bug: 30575790
Change-Id: Ida30d8fe7a1b210e98f1a0ea5d429a0112f9ef3f
Signed-off-by: Iliyan Malchev <malchev@google.com>
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 08be2eb..7e1a0ab 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -81,6 +81,7 @@
     android_text_StaticLayout.cpp \
     android_os_Debug.cpp \
     android_os_HwBinder.cpp \
+    android_os_HwBlob.cpp \
     android_os_HwParcel.cpp \
     android_os_HwRemoteBinder.cpp \
     android_os_MemoryFile.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 109d3fb..07392c4 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -157,6 +157,7 @@
 extern int register_android_nio_utils(JNIEnv* env);
 extern int register_android_os_Debug(JNIEnv* env);
 extern int register_android_os_HwBinder(JNIEnv *env);
+extern int register_android_os_HwBlob(JNIEnv *env);
 extern int register_android_os_HwParcel(JNIEnv *env);
 extern int register_android_os_HwRemoteBinder(JNIEnv *env);
 extern int register_android_os_MessageQueue(JNIEnv* env);
@@ -1291,6 +1292,7 @@
     REG_JNI(register_android_os_Binder),
     REG_JNI(register_android_os_Parcel),
     REG_JNI(register_android_os_HwBinder),
+    REG_JNI(register_android_os_HwBlob),
     REG_JNI(register_android_os_HwParcel),
     REG_JNI(register_android_os_HwRemoteBinder),
     REG_JNI(register_android_nio_utils),
diff --git a/core/jni/android_os_HwBlob.cpp b/core/jni/android_os_HwBlob.cpp
new file mode 100644
index 0000000..6972cf1
--- /dev/null
+++ b/core/jni/android_os_HwBlob.cpp
@@ -0,0 +1,452 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "android_os_HwBlob"
+#include <android-base/logging.h>
+
+#include "android_os_HwBlob.h"
+
+#include "android_os_HwParcel.h"
+
+#include <JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <hwbinder/Status.h>
+#include <nativehelper/ScopedLocalRef.h>
+
+#include "core_jni_helpers.h"
+
+using android::AndroidRuntime;
+using android::hardware::hidl_string;
+
+#define PACKAGE_PATH    "android/os"
+#define CLASS_NAME      "HwBlob"
+#define CLASS_PATH      PACKAGE_PATH "/" CLASS_NAME
+
+namespace android {
+
+static struct fields_t {
+    jfieldID contextID;
+    jmethodID constructID;
+
+} gFields;
+
+// static
+void JHwBlob::InitClass(JNIEnv *env) {
+    ScopedLocalRef<jclass> clazz(
+            env, FindClassOrDie(env, CLASS_PATH));
+
+    gFields.contextID =
+        GetFieldIDOrDie(env, clazz.get(), "mNativeContext", "J");
+
+    gFields.constructID = GetMethodIDOrDie(env, clazz.get(), "<init>", "(I)V");
+}
+
+// static
+sp<JHwBlob> JHwBlob::SetNativeContext(
+        JNIEnv *env, jobject thiz, const sp<JHwBlob> &context) {
+    sp<JHwBlob> old = (JHwBlob *)env->GetLongField(thiz, gFields.contextID);
+
+    if (context != NULL) {
+        context->incStrong(NULL /* id */);
+    }
+
+    if (old != NULL) {
+        old->decStrong(NULL /* id */);
+    }
+
+    env->SetLongField(thiz, gFields.contextID, (long)context.get());
+
+    return old;
+}
+
+// static
+sp<JHwBlob> JHwBlob::GetNativeContext(JNIEnv *env, jobject thiz) {
+    return (JHwBlob *)env->GetLongField(thiz, gFields.contextID);
+}
+
+JHwBlob::JHwBlob(JNIEnv *env, jobject thiz, size_t size)
+    : mBuffer(nullptr),
+      mSize(size),
+      mOwnsBuffer(true),
+      mHandle(0) {
+    jclass clazz = env->GetObjectClass(thiz);
+    CHECK(clazz != NULL);
+
+    mClass = (jclass)env->NewGlobalRef(clazz);
+    mObject = env->NewWeakGlobalRef(thiz);
+
+    if (size > 0) {
+        mBuffer = malloc(size);
+    }
+}
+
+JHwBlob::~JHwBlob() {
+    if (mOwnsBuffer) {
+        free(mBuffer);
+        mBuffer = nullptr;
+    }
+
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+    env->DeleteWeakGlobalRef(mObject);
+    mObject = NULL;
+
+    env->DeleteGlobalRef(mClass);
+    mClass = NULL;
+}
+
+void JHwBlob::setTo(const void *ptr, size_t handle) {
+    CHECK_EQ(mSize, 0u);
+    CHECK(mBuffer == nullptr);
+
+    mBuffer = const_cast<void *>(ptr);
+    mSize = SIZE_MAX;  // XXX
+    mOwnsBuffer = false;
+    mHandle = handle;
+}
+
+status_t JHwBlob::getHandle(size_t *handle) const {
+    if (mOwnsBuffer) {
+        return INVALID_OPERATION;
+    }
+
+    *handle = mHandle;
+
+    return OK;
+}
+
+status_t JHwBlob::read(size_t offset, void *data, size_t size) const {
+    if (offset + size > mSize) {
+        return -ERANGE;
+    }
+
+    memcpy(data, (const uint8_t *)mBuffer + offset, size);
+
+    return OK;
+}
+
+status_t JHwBlob::write(size_t offset, const void *data, size_t size) {
+    if (offset + size > mSize) {
+        return -ERANGE;
+    }
+
+    memcpy((uint8_t *)mBuffer + offset, data, size);
+
+    return OK;
+}
+
+status_t JHwBlob::getString(size_t offset, const hidl_string **s) const {
+    if ((offset + sizeof(hidl_string)) > mSize) {
+        return -ERANGE;
+    }
+
+    *s = reinterpret_cast<const hidl_string *>(
+            (const uint8_t *)mBuffer + offset);
+
+    return OK;
+}
+
+const void *JHwBlob::data() const {
+    return mBuffer;
+}
+
+size_t JHwBlob::size() const {
+    return mSize;
+}
+
+status_t JHwBlob::putBlob(size_t offset, const sp<JHwBlob> &blob) {
+    size_t index = mSubBlobs.add();
+    BlobInfo *info = &mSubBlobs.editItemAt(index);
+
+    info->mOffset = offset;
+    info->mBlob = blob;
+
+    const void *data = blob->data();
+
+    return write(offset, &data, sizeof(data));
+}
+
+status_t JHwBlob::writeToParcel(hardware::Parcel *parcel) const {
+    size_t handle;
+    status_t err = parcel->writeBuffer(data(), size(), &handle);
+
+    if (err != OK) {
+        return err;
+    }
+
+    for (size_t i = 0; i < mSubBlobs.size(); ++i) {
+        const BlobInfo &info = mSubBlobs[i];
+
+        err = info.mBlob->writeEmbeddedToParcel(parcel, handle, info.mOffset);
+
+        if (err != OK) {
+            return err;
+        }
+    }
+
+    return OK;
+}
+
+status_t JHwBlob::writeEmbeddedToParcel(
+        hardware::Parcel *parcel,
+        size_t parentHandle,
+        size_t parentOffset) const {
+    size_t handle;
+    status_t err = parcel->writeEmbeddedBuffer(
+            data(), size(), &handle, parentHandle, parentOffset);
+
+    if (err != OK) {
+        return err;
+    }
+
+    for (size_t i = 0; i < mSubBlobs.size(); ++i) {
+        const BlobInfo &info = mSubBlobs[i];
+
+        err = info.mBlob->writeEmbeddedToParcel(parcel, handle, info.mOffset);
+
+        if (err != OK) {
+            return err;
+        }
+    }
+
+    return OK;
+}
+
+// static
+jobject JHwBlob::NewObject(JNIEnv *env, const void *ptr, size_t handle) {
+    jobject obj = JHwBlob::NewObject(env, 0 /* size */);
+    JHwBlob::GetNativeContext(env, obj)->setTo(ptr, handle);
+
+    return obj;
+}
+
+// static
+jobject JHwBlob::NewObject(JNIEnv *env, size_t size) {
+    ScopedLocalRef<jclass> clazz(env, FindClassOrDie(env, CLASS_PATH));
+
+    jmethodID constructID =
+        GetMethodIDOrDie(env, clazz.get(), "<init>", "(I)V");
+
+    // XXX Again cannot refer to gFields.constructID because InitClass may
+    // not have been called yet.
+
+    return env->NewObject(clazz.get(), constructID, size);
+}
+
+}  // namespace android
+
+////////////////////////////////////////////////////////////////////////////////
+
+using namespace android;
+
+static void releaseNativeContext(void *nativeContext) {
+    sp<JHwBlob> parcel = (JHwBlob *)nativeContext;
+
+    if (parcel != NULL) {
+        parcel->decStrong(NULL /* id */);
+    }
+}
+
+static jlong JHwBlob_native_init(JNIEnv *env) {
+    JHwBlob::InitClass(env);
+
+    return reinterpret_cast<jlong>(&releaseNativeContext);
+}
+
+static void JHwBlob_native_setup(
+        JNIEnv *env, jobject thiz, jint size) {
+    sp<JHwBlob> context = new JHwBlob(env, thiz, size);
+
+    JHwBlob::SetNativeContext(env, thiz, context);
+}
+
+#define DEFINE_BLOB_GETTER(Suffix,Type)                                        \
+static Type JHwBlob_native_get ## Suffix(                                      \
+        JNIEnv *env, jobject thiz, jlong offset) {                             \
+    sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);                   \
+                                                                               \
+    Type x;                                                                    \
+    status_t err = blob->read(offset, &x, sizeof(x));                          \
+                                                                               \
+    if (err != OK) {                                                           \
+        signalExceptionForError(env, err);                                     \
+        return 0;                                                              \
+    }                                                                          \
+                                                                               \
+    return x;                                                                  \
+}
+
+DEFINE_BLOB_GETTER(Int8,jbyte)
+DEFINE_BLOB_GETTER(Int16,jshort)
+DEFINE_BLOB_GETTER(Int32,jint)
+DEFINE_BLOB_GETTER(Int64,jlong)
+DEFINE_BLOB_GETTER(Float,jfloat)
+DEFINE_BLOB_GETTER(Double,jdouble)
+
+static jboolean JHwBlob_native_getBool(
+        JNIEnv *env, jobject thiz, jlong offset) {
+    sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
+
+    bool x;
+    status_t err = blob->read(offset, &x, sizeof(x));
+
+    if (err != OK) {
+        signalExceptionForError(env, err);
+        return 0;
+    }
+
+    return (jboolean)x;
+}
+
+static jstring JHwBlob_native_getString(
+        JNIEnv *env, jobject thiz, jlong offset) {
+    sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
+
+    const hidl_string *s;
+    status_t err = blob->getString(offset, &s);
+
+    if (err != OK) {
+        signalExceptionForError(env, err);
+        return nullptr;
+    }
+
+    return env->NewStringUTF(s->c_str());
+}
+
+#define DEFINE_BLOB_PUTTER(Suffix,Type)                                        \
+static void JHwBlob_native_put ## Suffix(                                      \
+        JNIEnv *env, jobject thiz, jlong offset, Type x) {                     \
+                                                                               \
+    sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);                   \
+                                                                               \
+    status_t err = blob->write(offset, &x, sizeof(x));                         \
+                                                                               \
+    if (err != OK) {                                                           \
+        signalExceptionForError(env, err);                                     \
+    }                                                                          \
+}
+
+DEFINE_BLOB_PUTTER(Int8,jbyte)
+DEFINE_BLOB_PUTTER(Int16,jshort)
+DEFINE_BLOB_PUTTER(Int32,jint)
+DEFINE_BLOB_PUTTER(Int64,jlong)
+DEFINE_BLOB_PUTTER(Float,jfloat)
+DEFINE_BLOB_PUTTER(Double,jdouble)
+
+static void JHwBlob_native_putBool(
+        JNIEnv *env, jobject thiz, jlong offset, jboolean x) {
+
+    sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
+
+    bool b = (bool)x;
+    status_t err = blob->write(offset, &b, sizeof(b));
+
+    if (err != OK) {
+        signalExceptionForError(env, err);
+    }
+}
+
+static void JHwBlob_native_putString(
+        JNIEnv *env, jobject thiz, jlong offset, jstring stringObj) {
+    if (stringObj == nullptr) {
+        jniThrowException(env, "java/lang/NullPointerException", nullptr);
+        return;
+    }
+
+    const char *s = env->GetStringUTFChars(stringObj, nullptr);
+
+    if (s == nullptr) {
+        return;
+    }
+
+    size_t size = strlen(s) + 1;
+    ScopedLocalRef<jobject> subBlobObj(env, JHwBlob::NewObject(env, size));
+    sp<JHwBlob> subBlob = JHwBlob::GetNativeContext(env, subBlobObj.get());
+    subBlob->write(0 /* offset */, s, size);
+
+    env->ReleaseStringUTFChars(stringObj, s);
+    s = nullptr;
+
+    hidl_string tmp;
+    tmp.setToExternal(static_cast<const char *>(subBlob->data()), size);
+
+    sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
+    blob->write(offset, &tmp, sizeof(tmp));
+    blob->putBlob(offset + hidl_string::kOffsetOfBuffer, subBlob);
+}
+
+static void JHwBlob_native_putBlob(
+        JNIEnv *env, jobject thiz, jlong offset, jobject blobObj) {
+    if (blobObj == nullptr) {
+        jniThrowException(env, "java/lang/NullPointerException", nullptr);
+        return;
+    }
+
+    sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
+    sp<JHwBlob> subBlob = JHwBlob::GetNativeContext(env, blobObj);
+
+    blob->putBlob(offset, subBlob);
+}
+
+static jlong JHwBlob_native_handle(JNIEnv *env, jobject thiz) {
+    size_t handle;
+    status_t err = JHwBlob::GetNativeContext(env, thiz)->getHandle(&handle);
+
+    if (err != OK) {
+        signalExceptionForError(env, err);
+        return 0;
+    }
+
+    return handle;
+}
+
+static JNINativeMethod gMethods[] = {
+    { "native_init", "()J", (void *)JHwBlob_native_init },
+    { "native_setup", "(I)V", (void *)JHwBlob_native_setup },
+
+    { "getBool", "(J)Z", (void *)JHwBlob_native_getBool },
+    { "getInt8", "(J)B", (void *)JHwBlob_native_getInt8 },
+    { "getInt16", "(J)S", (void *)JHwBlob_native_getInt16 },
+    { "getInt32", "(J)I", (void *)JHwBlob_native_getInt32 },
+    { "getInt64", "(J)J", (void *)JHwBlob_native_getInt64 },
+    { "getFloat", "(J)F", (void *)JHwBlob_native_getFloat },
+    { "getDouble", "(J)D", (void *)JHwBlob_native_getDouble },
+    { "getString", "(J)Ljava/lang/String;", (void *)JHwBlob_native_getString },
+
+    { "putBool", "(JZ)V", (void *)JHwBlob_native_putBool },
+    { "putInt8", "(JB)V", (void *)JHwBlob_native_putInt8 },
+    { "putInt16", "(JS)V", (void *)JHwBlob_native_putInt16 },
+    { "putInt32", "(JI)V", (void *)JHwBlob_native_putInt32 },
+    { "putInt64", "(JJ)V", (void *)JHwBlob_native_putInt64 },
+    { "putFloat", "(JF)V", (void *)JHwBlob_native_putFloat },
+    { "putDouble", "(JD)V", (void *)JHwBlob_native_putDouble },
+    { "putString", "(JLjava/lang/String;)V", (void *)JHwBlob_native_putString },
+
+    { "putBlob", "(JL" PACKAGE_PATH "/HwBlob;)V",
+        (void *)JHwBlob_native_putBlob },
+
+    { "handle", "()J", (void *)JHwBlob_native_handle },
+};
+
+namespace android {
+
+int register_android_os_HwBlob(JNIEnv *env) {
+    return RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods));
+}
+
+}  // namespace android
+
diff --git a/core/jni/android_os_HwBlob.h b/core/jni/android_os_HwBlob.h
new file mode 100644
index 0000000..6bd82e9
--- /dev/null
+++ b/core/jni/android_os_HwBlob.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_OS_HW_BLOB_H
+#define ANDROID_OS_HW_BLOB_H
+
+#include <android-base/macros.h>
+#include <jni.h>
+#include <hidl/HidlSupport.h>
+#include <utils/RefBase.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+struct JHwBlob : public RefBase {
+    static void InitClass(JNIEnv *env);
+
+    static sp<JHwBlob> SetNativeContext(
+            JNIEnv *env, jobject thiz, const sp<JHwBlob> &context);
+
+    static sp<JHwBlob> GetNativeContext(JNIEnv *env, jobject thiz);
+
+    static jobject NewObject(JNIEnv *env, const void *ptr, size_t handle);
+    static jobject NewObject(JNIEnv *env, size_t size);
+
+    JHwBlob(JNIEnv *env, jobject thiz, size_t size);
+
+    void setTo(const void *ptr, size_t handle);
+
+    status_t getHandle(size_t *handle) const;
+
+    status_t read(size_t offset, void *data, size_t size) const;
+    status_t write(size_t offset, const void *data, size_t size);
+
+    status_t getString(
+            size_t offset, const android::hardware::hidl_string **s) const;
+
+    const void *data() const;
+    size_t size() const;
+
+    status_t putBlob(size_t offset, const sp<JHwBlob> &blob);
+
+    status_t writeToParcel(hardware::Parcel *parcel) const;
+
+    status_t writeEmbeddedToParcel(
+            hardware::Parcel *parcel,
+            size_t parentHandle,
+            size_t parentOffset) const;
+
+protected:
+    virtual ~JHwBlob();
+
+private:
+    struct BlobInfo {
+        size_t mOffset;
+        sp<JHwBlob> mBlob;
+    };
+
+    jclass mClass;
+    jobject mObject;
+
+    void *mBuffer;
+    size_t mSize;
+    bool mOwnsBuffer;
+
+    size_t mHandle;
+
+    Vector<BlobInfo> mSubBlobs;
+
+    DISALLOW_COPY_AND_ASSIGN(JHwBlob);
+};
+
+int register_android_os_HwBlob(JNIEnv *env);
+
+}  // namespace android
+
+#endif  // ANDROID_OS_HW_BLOB_H
+
diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp
index 94918f6..226d61b 100644
--- a/core/jni/android_os_HwParcel.cpp
+++ b/core/jni/android_os_HwParcel.cpp
@@ -21,6 +21,7 @@
 #include "android_os_HwParcel.h"
 
 #include "android_os_HwBinder.h"
+#include "android_os_HwBlob.h"
 #include "android_os_HwRemoteBinder.h"
 
 #include <JNIHelp.h>
@@ -71,6 +72,7 @@
             break;
         }
 
+        case -ERANGE:
         case BAD_INDEX:
         {
             jniThrowException(env, "java/lang/IndexOutOfBoundsException", NULL);
@@ -200,8 +202,10 @@
 jobject JHwParcel::NewObject(JNIEnv *env) {
     ScopedLocalRef<jclass> clazz(env, FindClassOrDie(env, CLASS_PATH));
 
-    return env->NewObject(
-            clazz.get(), gFields.constructID, false /* allocate */);
+    jmethodID constructID =
+        GetMethodIDOrDie(env, clazz.get(), "<init>", "(Z)V");
+
+    return env->NewObject(clazz.get(), constructID, false /* allocate */);
 }
 
 void JHwParcel::setTransactCallback(
@@ -547,9 +551,10 @@
 
     sp<JHwParcel> impl = JHwParcel::GetNativeContext(env, thiz);
 
-    hidl_vec<bool> *vec =
-        (hidl_vec<bool> *)impl->getStorage()->allocTemporaryStorage(
-                sizeof(hidl_vec<bool>));
+    void *vecPtr =
+        impl->getStorage()->allocTemporaryStorage(sizeof(hidl_vec<bool>));
+
+    hidl_vec<bool> *vec = new (vecPtr) hidl_vec<bool>;
 
     jsize len = env->GetArrayLength(valObj);
 
@@ -917,9 +922,10 @@
 
     sp<JHwParcel> impl = JHwParcel::GetNativeContext(env, thiz);
 
-    string_vec *vec =
-        (string_vec *)impl->getStorage()->allocTemporaryStorage(
-                sizeof(string_vec));
+    void *vecPtr =
+        impl->getStorage()->allocTemporaryStorage(sizeof(string_vec));
+
+    string_vec *vec = new (vecPtr) string_vec;
 
     hidl_string *strings = impl->getStorage()->allocStringArray(len);
     vec->setToExternal(strings, len);
@@ -972,6 +978,57 @@
     return JHwRemoteBinder::NewObject(env, binder);
 }
 
+static jobject JHwParcel_native_readBuffer(JNIEnv *env, jobject thiz) {
+    hardware::Parcel *parcel =
+        JHwParcel::GetNativeContext(env, thiz)->getParcel();
+
+    size_t handle;
+    const void *ptr = parcel->readBuffer(&handle);
+
+    if (ptr == nullptr) {
+        jniThrowException(env, "java/util/NoSuchElementException", NULL);
+        return nullptr;
+    }
+
+    return JHwBlob::NewObject(env, ptr, handle);
+}
+
+static jobject JHwParcel_native_readEmbeddedBuffer(
+        JNIEnv *env, jobject thiz, jlong parentHandle, jlong offset) {
+    hardware::Parcel *parcel =
+        JHwParcel::GetNativeContext(env, thiz)->getParcel();
+
+    size_t childHandle;
+
+    const void *ptr =
+        parcel->readEmbeddedBuffer(&childHandle, parentHandle, offset);
+
+    if (ptr == nullptr) {
+        jniThrowException(env, "java/util/NoSuchElementException", NULL);
+        return 0;
+    }
+
+    return JHwBlob::NewObject(env, ptr, childHandle);
+}
+
+static void JHwParcel_native_writeBuffer(
+        JNIEnv *env, jobject thiz, jobject blobObj) {
+    if (blobObj == nullptr) {
+        jniThrowException(env, "java/lang/NullPointerException", NULL);
+        return;
+    }
+
+    hardware::Parcel *parcel =
+        JHwParcel::GetNativeContext(env, thiz)->getParcel();
+
+    sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, blobObj);
+    status_t err = blob->writeToParcel(parcel);
+
+    if (err != OK) {
+        signalExceptionForError(env, err);
+    }
+}
+
 static JNINativeMethod gMethods[] = {
     { "native_init", "()J", (void *)JHwParcel_native_init },
     { "native_setup", "(Z)V", (void *)JHwParcel_native_setup },
@@ -1062,6 +1119,15 @@
         (void *)JHwParcel_native_releaseTemporaryStorage },
 
     { "send", "()V", (void *)JHwParcel_native_send },
+
+    { "readBuffer", "()L" PACKAGE_PATH "/HwBlob;",
+        (void *)JHwParcel_native_readBuffer },
+
+    { "readEmbeddedBuffer", "(JJ)L" PACKAGE_PATH "/HwBlob;",
+        (void *)JHwParcel_native_readEmbeddedBuffer },
+
+    { "writeBuffer", "(L" PACKAGE_PATH "/HwBlob;)V",
+        (void *)JHwParcel_native_writeBuffer },
 };
 
 namespace android {
diff --git a/core/jni/hwbinder/EphemeralStorage.cpp b/core/jni/hwbinder/EphemeralStorage.cpp
index e508708..187beee 100644
--- a/core/jni/hwbinder/EphemeralStorage.cpp
+++ b/core/jni/hwbinder/EphemeralStorage.cpp
@@ -99,9 +99,9 @@
     item.mPtr = (void *)val;                                                   \
     mItems.push_back(item);                                                    \
                                                                                \
-    hidl_vec<Type> *vec =                                                      \
-        (hidl_vec<Type> *)allocTemporaryStorage(sizeof(hidl_vec<Type>));       \
+    void *vecPtr = allocTemporaryStorage(sizeof(hidl_vec<Type>));              \
                                                                                \
+    hidl_vec<Type> *vec = new (vecPtr) hidl_vec<Type>;                         \
     vec->setToExternal(const_cast<Type *>(val), len);                          \
                                                                                \
     return vec;                                                                \