/* * 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_HwParcel" #include #include "android_os_HwParcel.h" #include "android_os_HwBinder.h" #include "android_os_HwBlob.h" #include "android_os_NativeHandle.h" #include "android_os_HwRemoteBinder.h" #include #include #include #include #include #include "core_jni_helpers.h" using android::AndroidRuntime; using ::android::hardware::hidl_handle; using ::android::hardware::hidl_string; using ::android::hardware::hidl_vec; #define PACKAGE_PATH "android/os" #define CLASS_NAME "HwParcel" #define CLASS_PATH PACKAGE_PATH "/" CLASS_NAME namespace android { static struct fields_t { jfieldID contextID; jmethodID constructID; } gFields; void signalExceptionForError(JNIEnv *env, status_t err, bool canThrowRemoteException) { switch (err) { case OK: break; case NO_MEMORY: { jniThrowException(env, "java/lang/OutOfMemoryError", NULL); break; } case INVALID_OPERATION: { jniThrowException( env, "java/lang/UnsupportedOperationException", NULL); break; } case BAD_VALUE: { jniThrowException(env, "java/lang/IllegalArgumentException", NULL); break; } case -ERANGE: case BAD_INDEX: { jniThrowException(env, "java/lang/IndexOutOfBoundsException", NULL); break; } case BAD_TYPE: { jniThrowException(env, "java/lang/IllegalArgumentException", NULL); break; } case NAME_NOT_FOUND: { jniThrowException(env, "java/util/NoSuchElementException", NULL); break; } case PERMISSION_DENIED: { jniThrowException(env, "java/lang/SecurityException", NULL); break; } case NO_INIT: { jniThrowException( env, "java/lang/RuntimeException", "Not initialized"); break; } case ALREADY_EXISTS: { jniThrowException( env, "java/lang/RuntimeException", "Item already exists"); break; } default: { std::stringstream ss; ss << "HwBinder Error: (" << err << ")"; jniThrowException( env, canThrowRemoteException ? "android/os/RemoteException" : "java/lang/RuntimeException", ss.str().c_str()); break; } } } // static void JHwParcel::InitClass(JNIEnv *env) { ScopedLocalRef clazz( env, FindClassOrDie(env, CLASS_PATH)); gFields.contextID = GetFieldIDOrDie(env, clazz.get(), "mNativeContext", "J"); gFields.constructID = GetMethodIDOrDie(env, clazz.get(), "", "(Z)V"); } // static sp JHwParcel::SetNativeContext( JNIEnv *env, jobject thiz, const sp &context) { sp old = (JHwParcel *)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 JHwParcel::GetNativeContext(JNIEnv *env, jobject thiz) { return (JHwParcel *)env->GetLongField(thiz, gFields.contextID); } JHwParcel::JHwParcel(JNIEnv *env, jobject thiz) : mParcel(NULL), mOwnsParcel(false), mTransactCallback(nullptr), mWasSent(false) { } JHwParcel::~JHwParcel() { JNIEnv *env = AndroidRuntime::getJNIEnv(); mStorage.release(env); setParcel(NULL, false /* assumeOwnership */); } hardware::Parcel *JHwParcel::getParcel() { return mParcel; } EphemeralStorage *JHwParcel::getStorage() { return &mStorage; } void JHwParcel::setParcel(hardware::Parcel *parcel, bool assumeOwnership) { if (mParcel && mOwnsParcel) { delete mParcel; } mParcel = parcel; mOwnsParcel = assumeOwnership; } // static jobject JHwParcel::NewObject(JNIEnv *env) { ScopedLocalRef clazz(env, FindClassOrDie(env, CLASS_PATH)); jmethodID constructID = GetMethodIDOrDie(env, clazz.get(), "", "(Z)V"); return env->NewObject(clazz.get(), constructID, false /* allocate */); } void JHwParcel::setTransactCallback( ::android::hardware::IBinder::TransactCallback cb) { mTransactCallback = cb; } void JHwParcel::send() { CHECK(mTransactCallback != nullptr); CHECK(mParcel != nullptr); mTransactCallback(*mParcel); mTransactCallback = nullptr; mWasSent = true; } bool JHwParcel::wasSent() const { return mWasSent; } } // namespace android //////////////////////////////////////////////////////////////////////////////// using namespace android; static void releaseNativeContext(void *nativeContext) { sp parcel = (JHwParcel *)nativeContext; if (parcel != NULL) { parcel->decStrong(NULL /* id */); } } static jlong JHwParcel_native_init(JNIEnv *env) { JHwParcel::InitClass(env); return reinterpret_cast(&releaseNativeContext); } static void JHwParcel_native_setup( JNIEnv *env, jobject thiz, jboolean allocate) { sp context = new JHwParcel(env, thiz); if (allocate) { context->setParcel(new hardware::Parcel, true /* assumeOwnership */); } JHwParcel::SetNativeContext(env, thiz, context); } static void JHwParcel_native_writeInterfaceToken( JNIEnv *env, jobject thiz, jstring interfaceNameObj) { if (interfaceNameObj == NULL) { jniThrowException(env, "java/lang/NullPointerException", NULL); return; } const jchar *interfaceName = env->GetStringCritical(interfaceNameObj, NULL); if (interfaceName) { String8 nameCopy = String8(String16( reinterpret_cast(interfaceName), env->GetStringLength(interfaceNameObj))); env->ReleaseStringCritical(interfaceNameObj, interfaceName); interfaceName = NULL; hardware::Parcel *parcel = JHwParcel::GetNativeContext(env, thiz)->getParcel(); status_t err = parcel->writeInterfaceToken(nameCopy.string()); signalExceptionForError(env, err); } } static void JHwParcel_native_enforceInterface( JNIEnv *env, jobject thiz, jstring interfaceNameObj) { // XXX original binder Parcel enforceInterface implementation does some // mysterious things regarding strictModePolicy(), figure out if we need // that here as well. if (interfaceNameObj == NULL) { jniThrowException(env, "java/lang/NullPointerException", NULL); return; } const jchar *interfaceName = env->GetStringCritical(interfaceNameObj, NULL); if (interfaceName) { String8 interfaceNameCopy = String8(String16( reinterpret_cast(interfaceName), env->GetStringLength(interfaceNameObj))); env->ReleaseStringCritical(interfaceNameObj, interfaceName); interfaceName = NULL; hardware::Parcel *parcel = JHwParcel::GetNativeContext(env, thiz)->getParcel(); bool valid = parcel->enforceInterface(interfaceNameCopy.string()); if (!valid) { jniThrowException( env, "java/lang/SecurityException", "HWBinder invocation to an incorrect interface"); } } } #define DEFINE_PARCEL_WRITER(Suffix,Type) \ static void JHwParcel_native_write ## Suffix( \ JNIEnv *env, jobject thiz, Type val) { \ hardware::Parcel *parcel = \ JHwParcel::GetNativeContext(env, thiz)->getParcel(); \ \ status_t err = parcel->write ## Suffix(val); \ signalExceptionForError(env, err); \ } #define DEFINE_PARCEL_READER(Suffix,Type) \ static Type JHwParcel_native_read ## Suffix( \ JNIEnv *env, jobject thiz) { \ hardware::Parcel *parcel = \ JHwParcel::GetNativeContext(env, thiz)->getParcel(); \ \ Type val; \ status_t err = parcel->read ## Suffix(&val); \ signalExceptionForError(env, err); \ \ return val; \ } DEFINE_PARCEL_WRITER(Bool,jboolean) DEFINE_PARCEL_WRITER(Int8,jbyte) DEFINE_PARCEL_WRITER(Int16,jshort) DEFINE_PARCEL_WRITER(Int32,jint) DEFINE_PARCEL_WRITER(Int64,jlong) DEFINE_PARCEL_WRITER(Float,jfloat) DEFINE_PARCEL_WRITER(Double,jdouble) DEFINE_PARCEL_READER(Int8,jbyte) DEFINE_PARCEL_READER(Int16,jshort) DEFINE_PARCEL_READER(Int32,jint) DEFINE_PARCEL_READER(Int64,jlong) DEFINE_PARCEL_READER(Float,jfloat) DEFINE_PARCEL_READER(Double,jdouble) static jboolean JHwParcel_native_readBool(JNIEnv *env, jobject thiz) { hardware::Parcel *parcel = JHwParcel::GetNativeContext(env, thiz)->getParcel(); bool val; status_t err = parcel->readBool(&val); signalExceptionForError(env, err); return (jboolean)val; } static void JHwParcel_native_writeStatus( JNIEnv *env, jobject thiz, jint statusCode) { using hardware::Status; Status status; switch (statusCode) { case 0: // kStatusSuccess status = Status::ok(); break; case -1: // kStatusError status = Status::fromStatusT(UNKNOWN_ERROR); break; default: CHECK(!"Should not be here"); } hardware::Parcel *parcel = JHwParcel::GetNativeContext(env, thiz)->getParcel(); status_t err = ::android::hardware::writeToParcel(status, parcel); signalExceptionForError(env, err); } static void JHwParcel_native_verifySuccess(JNIEnv *env, jobject thiz) { using hardware::Status; hardware::Parcel *parcel = JHwParcel::GetNativeContext(env, thiz)->getParcel(); Status status; status_t err = ::android::hardware::readFromParcel(&status, *parcel); signalExceptionForError(env, err); if (!status.isOk()) { signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */); } } static void JHwParcel_native_release( JNIEnv *env, jobject thiz) { JHwParcel::GetNativeContext(env, thiz)->setParcel(NULL, false /* assumeOwnership */); } static void JHwParcel_native_releaseTemporaryStorage( JNIEnv *env, jobject thiz) { JHwParcel::GetNativeContext(env, thiz)->getStorage()->release(env); } static void JHwParcel_native_send(JNIEnv *env, jobject thiz) { JHwParcel::GetNativeContext(env, thiz)->send(); } static void JHwParcel_native_writeString( JNIEnv *env, jobject thiz, jstring valObj) { if (valObj == NULL) { jniThrowException(env, "java/lang/NullPointerException", NULL); return; } sp impl = JHwParcel::GetNativeContext(env, thiz); const hidl_string *s = impl->getStorage()->allocTemporaryString(env, valObj); hardware::Parcel *parcel = impl->getParcel(); size_t parentHandle; status_t err = parcel->writeBuffer(s, sizeof(*s), &parentHandle); if (err == OK) { err = ::android::hardware::writeEmbeddedToParcel( *s, parcel, parentHandle, 0 /* parentOffset */); } signalExceptionForError(env, err); } static void JHwParcel_native_writeNativeHandle(JNIEnv *env, jobject thiz, jobject valObj) { sp impl = JHwParcel::GetNativeContext(env, thiz); EphemeralStorage *storage = impl->getStorage(); native_handle_t *handle = JNativeHandle::MakeCppNativeHandle(env, valObj, storage); hardware::Parcel *parcel = impl->getParcel(); status_t err = parcel->writeNativeHandleNoDup(handle); signalExceptionForError(env, err); } #define DEFINE_PARCEL_VECTOR_WRITER(Suffix,Type) \ static void JHwParcel_native_write ## Suffix ## Vector( \ JNIEnv *env, jobject thiz, Type ## Array valObj) { \ if (valObj == NULL) { \ jniThrowException(env, "java/lang/NullPointerException", NULL); \ return; \ } \ \ sp impl = JHwParcel::GetNativeContext(env, thiz); \ \ const hidl_vec *vec = \ impl->getStorage()->allocTemporary ## Suffix ## Vector(env, valObj); \ \ hardware::Parcel *parcel = impl->getParcel(); \ \ size_t parentHandle; \ status_t err = parcel->writeBuffer(vec, sizeof(*vec), &parentHandle); \ \ if (err == OK) { \ size_t childHandle; \ \ err = ::android::hardware::writeEmbeddedToParcel( \ *vec, \ parcel, \ parentHandle, \ 0 /* parentOffset */, \ &childHandle); \ } \ \ signalExceptionForError(env, err); \ } DEFINE_PARCEL_VECTOR_WRITER(Int8,jbyte) DEFINE_PARCEL_VECTOR_WRITER(Int16,jshort) DEFINE_PARCEL_VECTOR_WRITER(Int32,jint) DEFINE_PARCEL_VECTOR_WRITER(Int64,jlong) DEFINE_PARCEL_VECTOR_WRITER(Float,jfloat) DEFINE_PARCEL_VECTOR_WRITER(Double,jdouble) static void JHwParcel_native_writeBoolVector( JNIEnv *env, jobject thiz, jbooleanArray valObj) { if (valObj == NULL) { jniThrowException(env, "java/lang/NullPointerException", NULL); return; } sp impl = JHwParcel::GetNativeContext(env, thiz); void *vecPtr = impl->getStorage()->allocTemporaryStorage(sizeof(hidl_vec)); hidl_vec *vec = new (vecPtr) hidl_vec; jsize len = env->GetArrayLength(valObj); jboolean *src = env->GetBooleanArrayElements(valObj, nullptr); bool *dst = (bool *)impl->getStorage()->allocTemporaryStorage(len * sizeof(bool)); for (jsize i = 0; i < len; ++i) { dst[i] = src[i]; } env->ReleaseBooleanArrayElements(valObj, src, 0 /* mode */); src = nullptr; vec->setToExternal(dst, len); hardware::Parcel *parcel = impl->getParcel(); size_t parentHandle; status_t err = parcel->writeBuffer(vec, sizeof(*vec), &parentHandle); if (err == OK) { size_t childHandle; err = ::android::hardware::writeEmbeddedToParcel( *vec, parcel, parentHandle, 0 /* parentOffset */, &childHandle); } signalExceptionForError(env, err); } template static void WriteHidlVector(JNIEnv *env, jobject thiz, const hidl_vec &vec) { hardware::Parcel *parcel = JHwParcel::GetNativeContext(env, thiz)->getParcel(); size_t parentHandle; status_t err = parcel->writeBuffer(&vec, sizeof(vec), &parentHandle); if (err == OK) { size_t childHandle; err = ::android::hardware::writeEmbeddedToParcel( vec, parcel, parentHandle, 0 /* parentOffset */, &childHandle); for (size_t i = 0; (err == OK) && (i < vec.size()); ++i) { err = ::android::hardware::writeEmbeddedToParcel( vec[i], parcel, childHandle, i * sizeof(T)); } } signalExceptionForError(env, err); } static void JHwParcel_native_writeStringVector( JNIEnv *env, jobject thiz, jobjectArray arrayObj) { if (arrayObj == nullptr) { jniThrowException(env, "java/lang/NullPointerException", nullptr); return; } sp impl = JHwParcel::GetNativeContext(env, thiz); EphemeralStorage *storage = impl->getStorage(); void *vecPtr = storage->allocTemporaryStorage(sizeof(hidl_vec)); hidl_vec *vec = new (vecPtr) hidl_vec(); jsize len = env->GetArrayLength(arrayObj); hidl_string *strings = storage->allocStringArray(len); vec->setToExternal(strings, len, false /* shouldOwn */); for (jsize i = 0; i < len; ++i) { ScopedLocalRef stringObj(env, (jstring) env->GetObjectArrayElement(arrayObj, i)); const hidl_string *s = storage->allocTemporaryString(env, stringObj.get()); strings[i].setToExternal(s->c_str(), s->size()); } WriteHidlVector(env, thiz, *vec); } static void JHwParcel_native_writeNativeHandleVector( JNIEnv *env, jobject thiz, jobjectArray jHandleArray) { if (jHandleArray == nullptr) { jniThrowException(env, "java/lang/NullPointerException", nullptr); return; } sp impl = JHwParcel::GetNativeContext(env, thiz); EphemeralStorage *storage = impl->getStorage(); void *vecPtr = storage->allocTemporaryStorage(sizeof(hidl_vec)); hidl_vec *vec = new (vecPtr) hidl_vec(); jsize len = env->GetArrayLength(jHandleArray); hidl_handle *handles = static_cast( storage->allocTemporaryStorage(len * sizeof(hidl_handle))); vec->setToExternal(handles, len, false /* shouldOwn */); for (jsize i = 0; i < len; i++) { ScopedLocalRef jHandle(env, env->GetObjectArrayElement(jHandleArray, i)); native_handle_t* handle = JNativeHandle::MakeCppNativeHandle(env, jHandle.get(), storage); new (&(handles[i])) hidl_handle(); handles[i].setTo(handle, false /* shouldOwn */); } WriteHidlVector(env, thiz, *vec); } static void JHwParcel_native_writeStrongBinder( JNIEnv *env, jobject thiz, jobject binderObj) { sp binder; if (binderObj != NULL) { ScopedLocalRef hwBinderKlass(env, FindClassOrDie(env, PACKAGE_PATH "/HwBinder")); ScopedLocalRef hwRemoteBinderKlass( env, FindClassOrDie(env, PACKAGE_PATH "/HwRemoteBinder")); if (env->IsInstanceOf(binderObj, hwBinderKlass.get())) { binder = JHwBinder::GetNativeBinder(env, binderObj); } else if (env->IsInstanceOf(binderObj, hwRemoteBinderKlass.get())) { binder = JHwRemoteBinder::GetNativeContext( env, binderObj)->getBinder(); } else { signalExceptionForError(env, INVALID_OPERATION); return; } } hardware::Parcel *parcel = JHwParcel::GetNativeContext(env, thiz)->getParcel(); status_t err = parcel->writeStrongBinder(binder); signalExceptionForError(env, err); } static jstring MakeStringObjFromHidlString(JNIEnv *env, const hidl_string &s) { String16 utf16String(s.c_str(), s.size()); return env->NewString( reinterpret_cast(utf16String.string()), utf16String.size()); } static jstring JHwParcel_native_readString(JNIEnv *env, jobject thiz) { hardware::Parcel *parcel = JHwParcel::GetNativeContext(env, thiz)->getParcel(); size_t parentHandle; const hidl_string *s; status_t err = parcel->readBuffer(sizeof(*s), &parentHandle, reinterpret_cast(&s)); if (err != OK) { signalExceptionForError(env, err); return NULL; } err = ::android::hardware::readEmbeddedFromParcel( const_cast(*s), *parcel, parentHandle, 0 /* parentOffset */); if (err != OK) { signalExceptionForError(env, err); return NULL; } return MakeStringObjFromHidlString(env, *s); } static jobject ReadNativeHandle(JNIEnv *env, jobject thiz, jboolean embedded, jlong parentHandle, jlong offset) { hardware::Parcel *parcel = JHwParcel::GetNativeContext(env, thiz)->getParcel(); const native_handle_t *handle = nullptr; status_t err = OK; if (embedded) { err = parcel->readNullableEmbeddedNativeHandle(parentHandle, offset, &handle); } else { err = parcel->readNullableNativeHandleNoDup(&handle); } if (err != OK) { signalExceptionForError(env, err); return nullptr; } return JNativeHandle::MakeJavaNativeHandleObj(env, handle); } static jobject JHwParcel_native_readNativeHandle(JNIEnv *env, jobject thiz) { return ReadNativeHandle(env, thiz, false /*embedded*/, 0L /*parentHandle*/, 0L /*offset*/); } static jobject JHwParcel_native_readEmbeddedNativeHandle( JNIEnv *env, jobject thiz, jlong parentHandle, jlong offset) { return ReadNativeHandle(env, thiz, true /*embedded*/, parentHandle, offset); } #define DEFINE_PARCEL_VECTOR_READER(Suffix,Type,NewType) \ static Type ## Array JHwParcel_native_read ## Suffix ## Vector( \ JNIEnv *env, jobject thiz) { \ hardware::Parcel *parcel = \ JHwParcel::GetNativeContext(env, thiz)->getParcel(); \ size_t parentHandle; \ \ const hidl_vec *vec; \ status_t err = parcel->readBuffer(sizeof(*vec), &parentHandle, \ reinterpret_cast(&vec)); \ \ if (err != OK) { \ signalExceptionForError(env, err); \ return NULL; \ } \ \ size_t childHandle; \ \ err = ::android::hardware::readEmbeddedFromParcel( \ const_cast &>(*vec), \ *parcel, \ parentHandle, \ 0 /* parentOffset */, \ &childHandle); \ \ if (err != OK) { \ signalExceptionForError(env, err); \ return NULL; \ } \ \ Type ## Array valObj = env->New ## NewType ## Array(vec->size()); \ env->Set ## NewType ## ArrayRegion(valObj, 0, vec->size(), &(*vec)[0]); \ \ return valObj; \ } DEFINE_PARCEL_VECTOR_READER(Int8,jbyte,Byte) DEFINE_PARCEL_VECTOR_READER(Int16,jshort,Short) DEFINE_PARCEL_VECTOR_READER(Int32,jint,Int) DEFINE_PARCEL_VECTOR_READER(Int64,jlong,Long) DEFINE_PARCEL_VECTOR_READER(Float,jfloat,Float) DEFINE_PARCEL_VECTOR_READER(Double,jdouble,Double) static jbooleanArray JHwParcel_native_readBoolVector(JNIEnv *env, jobject thiz) { hardware::Parcel *parcel = JHwParcel::GetNativeContext(env, thiz)->getParcel(); size_t parentHandle; const hidl_vec *vec; status_t err = parcel->readBuffer(sizeof(*vec), &parentHandle, reinterpret_cast(&vec)); if (err != OK) { signalExceptionForError(env, err); return NULL; } size_t childHandle; err = ::android::hardware::readEmbeddedFromParcel( const_cast &>(*vec), *parcel, parentHandle, 0 /* parentOffset */, &childHandle); if (err != OK) { signalExceptionForError(env, err); return NULL; } jbooleanArray valObj = env->NewBooleanArray(vec->size()); for (size_t i = 0; i < vec->size(); ++i) { jboolean x = (*vec)[i]; env->SetBooleanArrayRegion(valObj, i, 1, &x); } return valObj; } static jobjectArray MakeStringArray( JNIEnv *env, const hidl_string *array, size_t size) { ScopedLocalRef stringKlass( env, env->FindClass("java/lang/String")); // XXX Why can't I use ScopedLocalRef<> for the arrayObj and the stringObjs? jobjectArray arrayObj = env->NewObjectArray(size, stringKlass.get(), NULL); for (size_t i = 0; i < size; ++i) { jstring stringObj = MakeStringObjFromHidlString(env, array[i]); env->SetObjectArrayElement( arrayObj, i, stringObj); } return arrayObj; } template static const hidl_vec *ReadHidlVector(JNIEnv *env, jobject thiz) { const hidl_vec *vec; hardware::Parcel *parcel = JHwParcel::GetNativeContext(env, thiz)->getParcel(); size_t parentHandle; status_t err = parcel->readBuffer(sizeof(hidl_vec), &parentHandle, reinterpret_cast(&vec)); if (err == OK) { size_t childHandle; err = ::android::hardware::readEmbeddedFromParcel( const_cast &>(*vec), *parcel, parentHandle, 0 /* parentOffset */, &childHandle); for (size_t i = 0; (err == OK) && (i < vec->size()); i++) { err = android::hardware::readEmbeddedFromParcel( const_cast((*vec)[i]), *parcel, childHandle, i * sizeof(T) /* parentOffset */); } } if (err != OK) { signalExceptionForError(env, err); return nullptr; } return vec; } static jobjectArray JHwParcel_native_readStringVector( JNIEnv *env, jobject thiz) { const hidl_vec *vec = ReadHidlVector(env, thiz); return MakeStringArray(env, &(*vec)[0], vec->size()); } static jobjectArray JHwParcel_native_readNativeHandleVector( JNIEnv *env, jobject thiz) { const hidl_vec *vec = ReadHidlVector(env, thiz); jsize length = vec->size(); jobjectArray objArray = JNativeHandle::AllocJavaNativeHandleObjArray( env, length); for (jsize i = 0; i < length; i++) { jobject jHandle = JNativeHandle::MakeJavaNativeHandleObj(env, (*vec)[i].getNativeHandle()); env->SetObjectArrayElement(objArray, i, jHandle); } return objArray; } static jobject JHwParcel_native_readStrongBinder(JNIEnv *env, jobject thiz) { hardware::Parcel *parcel = JHwParcel::GetNativeContext(env, thiz)->getParcel(); sp binder = parcel->readStrongBinder(); if (binder == NULL) { return NULL; } return JHwRemoteBinder::NewObject(env, binder); } static jobject JHwParcel_native_readBuffer(JNIEnv *env, jobject thiz, jlong expectedSize) { hardware::Parcel *parcel = JHwParcel::GetNativeContext(env, thiz)->getParcel(); size_t handle; const void *ptr; if (expectedSize < 0) { jniThrowException(env, "java/lang/IllegalArgumentException", NULL); return nullptr; } status_t status = parcel->readBuffer(expectedSize, &handle, &ptr); if (status != OK) { jniThrowException(env, "java/util/NoSuchElementException", NULL); return nullptr; } return JHwBlob::NewObject(env, ptr, handle); } static jobject JHwParcel_native_readEmbeddedBuffer( JNIEnv *env, jobject thiz, jlong expectedSize, jlong parentHandle, jlong offset, jboolean nullable) { hardware::Parcel *parcel = JHwParcel::GetNativeContext(env, thiz)->getParcel(); size_t childHandle; const void *ptr; status_t status = parcel->readNullableEmbeddedBuffer(expectedSize, &childHandle, parentHandle, offset, &ptr); if (expectedSize < 0) { jniThrowException(env, "java/lang/IllegalArgumentException", NULL); return nullptr; } if (status != OK) { jniThrowException(env, "java/util/NoSuchElementException", NULL); return 0; } else if (status == OK && !nullable && ptr == nullptr) { jniThrowException(env, "java/lang/NullPointerException", 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 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 }, { "writeInterfaceToken", "(Ljava/lang/String;)V", (void *)JHwParcel_native_writeInterfaceToken }, { "writeBool", "(Z)V", (void *)JHwParcel_native_writeBool }, { "writeInt8", "(B)V", (void *)JHwParcel_native_writeInt8 }, { "writeInt16", "(S)V", (void *)JHwParcel_native_writeInt16 }, { "writeInt32", "(I)V", (void *)JHwParcel_native_writeInt32 }, { "writeInt64", "(J)V", (void *)JHwParcel_native_writeInt64 }, { "writeFloat", "(F)V", (void *)JHwParcel_native_writeFloat }, { "writeDouble", "(D)V", (void *)JHwParcel_native_writeDouble }, { "writeString", "(Ljava/lang/String;)V", (void *)JHwParcel_native_writeString }, { "writeNativeHandle", "(L" PACKAGE_PATH "/NativeHandle;)V", (void *)JHwParcel_native_writeNativeHandle }, { "writeBoolVector", "([Z)V", (void *)JHwParcel_native_writeBoolVector }, { "writeInt8Vector", "([B)V", (void *)JHwParcel_native_writeInt8Vector }, { "writeInt16Vector", "([S)V", (void *)JHwParcel_native_writeInt16Vector }, { "writeInt32Vector", "([I)V", (void *)JHwParcel_native_writeInt32Vector }, { "writeInt64Vector", "([J)V", (void *)JHwParcel_native_writeInt64Vector }, { "writeFloatVector", "([F)V", (void *)JHwParcel_native_writeFloatVector }, { "writeDoubleVector", "([D)V", (void *)JHwParcel_native_writeDoubleVector }, { "writeStringVector", "([Ljava/lang/String;)V", (void *)JHwParcel_native_writeStringVector }, { "writeNativeHandleVector", "([L" PACKAGE_PATH "/NativeHandle;)V", (void *)JHwParcel_native_writeNativeHandleVector }, { "writeStrongBinder", "(L" PACKAGE_PATH "/IHwBinder;)V", (void *)JHwParcel_native_writeStrongBinder }, { "enforceInterface", "(Ljava/lang/String;)V", (void *)JHwParcel_native_enforceInterface }, { "readBool", "()Z", (void *)JHwParcel_native_readBool }, { "readInt8", "()B", (void *)JHwParcel_native_readInt8 }, { "readInt16", "()S", (void *)JHwParcel_native_readInt16 }, { "readInt32", "()I", (void *)JHwParcel_native_readInt32 }, { "readInt64", "()J", (void *)JHwParcel_native_readInt64 }, { "readFloat", "()F", (void *)JHwParcel_native_readFloat }, { "readDouble", "()D", (void *)JHwParcel_native_readDouble }, { "readString", "()Ljava/lang/String;", (void *)JHwParcel_native_readString }, { "readNativeHandle", "()L" PACKAGE_PATH "/NativeHandle;", (void *)JHwParcel_native_readNativeHandle }, { "readEmbeddedNativeHandle", "(JJ)L" PACKAGE_PATH "/NativeHandle;", (void *)JHwParcel_native_readEmbeddedNativeHandle }, { "readBoolVectorAsArray", "()[Z", (void *)JHwParcel_native_readBoolVector }, { "readInt8VectorAsArray", "()[B", (void *)JHwParcel_native_readInt8Vector }, { "readInt16VectorAsArray", "()[S", (void *)JHwParcel_native_readInt16Vector }, { "readInt32VectorAsArray", "()[I", (void *)JHwParcel_native_readInt32Vector }, { "readInt64VectorAsArray", "()[J", (void *)JHwParcel_native_readInt64Vector }, { "readFloatVectorAsArray", "()[F", (void *)JHwParcel_native_readFloatVector }, { "readDoubleVectorAsArray", "()[D", (void *)JHwParcel_native_readDoubleVector }, { "readStringVectorAsArray", "()[Ljava/lang/String;", (void *)JHwParcel_native_readStringVector }, { "readNativeHandleAsArray", "()[L" PACKAGE_PATH "/NativeHandle;", (void *)JHwParcel_native_readNativeHandleVector }, { "readStrongBinder", "()L" PACKAGE_PATH "/IHwBinder;", (void *)JHwParcel_native_readStrongBinder }, { "writeStatus", "(I)V", (void *)JHwParcel_native_writeStatus }, { "verifySuccess", "()V", (void *)JHwParcel_native_verifySuccess }, { "releaseTemporaryStorage", "()V", (void *)JHwParcel_native_releaseTemporaryStorage }, { "send", "()V", (void *)JHwParcel_native_send }, { "readBuffer", "(J)L" PACKAGE_PATH "/HwBlob;", (void *)JHwParcel_native_readBuffer }, { "readEmbeddedBuffer", "(JJJZ)L" PACKAGE_PATH "/HwBlob;", (void *)JHwParcel_native_readEmbeddedBuffer }, { "writeBuffer", "(L" PACKAGE_PATH "/HwBlob;)V", (void *)JHwParcel_native_writeBuffer }, { "release", "()V", (void *)JHwParcel_native_release }, }; namespace android { int register_android_os_HwParcel(JNIEnv *env) { return RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods)); } } // namespace android