/*
|
* 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 <android-base/logging.h>
|
|
#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 <nativehelper/JNIHelp.h>
|
#include <android_runtime/AndroidRuntime.h>
|
#include <hidl/HidlTransportSupport.h>
|
#include <hidl/Status.h>
|
#include <nativehelper/ScopedLocalRef.h>
|
|
#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<jclass> clazz(
|
env, FindClassOrDie(env, CLASS_PATH));
|
|
gFields.contextID =
|
GetFieldIDOrDie(env, clazz.get(), "mNativeContext", "J");
|
|
gFields.constructID = GetMethodIDOrDie(env, clazz.get(), "<init>", "(Z)V");
|
}
|
|
// static
|
sp<JHwParcel> JHwParcel::SetNativeContext(
|
JNIEnv *env, jobject thiz, const sp<JHwParcel> &context) {
|
sp<JHwParcel> 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> 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<jclass> clazz(env, FindClassOrDie(env, CLASS_PATH));
|
|
jmethodID constructID =
|
GetMethodIDOrDie(env, clazz.get(), "<init>", "(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<JHwParcel> parcel = (JHwParcel *)nativeContext;
|
|
if (parcel != NULL) {
|
parcel->decStrong(NULL /* id */);
|
}
|
}
|
|
static jlong JHwParcel_native_init(JNIEnv *env) {
|
JHwParcel::InitClass(env);
|
|
return reinterpret_cast<jlong>(&releaseNativeContext);
|
}
|
|
static void JHwParcel_native_setup(
|
JNIEnv *env, jobject thiz, jboolean allocate) {
|
sp<JHwParcel> 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<const char16_t *>(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<const char16_t *>(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<JHwParcel> 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<JHwParcel> 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<JHwParcel> impl = JHwParcel::GetNativeContext(env, thiz); \
|
\
|
const hidl_vec<Type> *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<JHwParcel> impl = JHwParcel::GetNativeContext(env, thiz);
|
|
void *vecPtr =
|
impl->getStorage()->allocTemporaryStorage(sizeof(hidl_vec<bool>));
|
|
hidl_vec<bool> *vec = new (vecPtr) hidl_vec<bool>;
|
|
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<typename T>
|
static void WriteHidlVector(JNIEnv *env, jobject thiz, const hidl_vec<T> &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<JHwParcel> impl = JHwParcel::GetNativeContext(env, thiz);
|
EphemeralStorage *storage = impl->getStorage();
|
|
void *vecPtr = storage->allocTemporaryStorage(sizeof(hidl_vec<hidl_string>));
|
hidl_vec<hidl_string> *vec = new (vecPtr) hidl_vec<hidl_string>();
|
|
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<jstring> 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<JHwParcel> impl = JHwParcel::GetNativeContext(env, thiz);
|
EphemeralStorage *storage = impl->getStorage();
|
|
void *vecPtr = storage->allocTemporaryStorage(sizeof(hidl_vec<hidl_handle>));
|
hidl_vec<hidl_handle> *vec = new (vecPtr) hidl_vec<hidl_handle>();
|
|
jsize len = env->GetArrayLength(jHandleArray);
|
hidl_handle *handles = static_cast<hidl_handle *>(
|
storage->allocTemporaryStorage(len * sizeof(hidl_handle)));
|
|
vec->setToExternal(handles, len, false /* shouldOwn */);
|
for (jsize i = 0; i < len; i++) {
|
ScopedLocalRef<jobject> 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<hardware::IBinder> binder;
|
if (binderObj != NULL) {
|
ScopedLocalRef<jclass> hwBinderKlass(env, FindClassOrDie(env, PACKAGE_PATH "/HwBinder"));
|
|
ScopedLocalRef<jclass> 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<const jchar *>(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<const void**>(&s));
|
|
if (err != OK) {
|
signalExceptionForError(env, err);
|
return NULL;
|
}
|
|
err = ::android::hardware::readEmbeddedFromParcel(
|
const_cast<hidl_string &>(*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<Type> *vec; \
|
status_t err = parcel->readBuffer(sizeof(*vec), &parentHandle, \
|
reinterpret_cast<const void**>(&vec)); \
|
\
|
if (err != OK) { \
|
signalExceptionForError(env, err); \
|
return NULL; \
|
} \
|
\
|
size_t childHandle; \
|
\
|
err = ::android::hardware::readEmbeddedFromParcel( \
|
const_cast<hidl_vec<Type> &>(*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<bool> *vec;
|
status_t err = parcel->readBuffer(sizeof(*vec), &parentHandle,
|
reinterpret_cast<const void**>(&vec));
|
|
if (err != OK) {
|
signalExceptionForError(env, err);
|
return NULL;
|
}
|
|
size_t childHandle;
|
|
err = ::android::hardware::readEmbeddedFromParcel(
|
const_cast<hidl_vec<bool> &>(*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<jclass> 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<typename T>
|
static const hidl_vec<T> *ReadHidlVector(JNIEnv *env, jobject thiz) {
|
const hidl_vec<T> *vec;
|
|
hardware::Parcel *parcel = JHwParcel::GetNativeContext(env, thiz)->getParcel();
|
|
size_t parentHandle;
|
status_t err = parcel->readBuffer(sizeof(hidl_vec<T>),
|
&parentHandle, reinterpret_cast<const void **>(&vec));
|
|
if (err == OK) {
|
size_t childHandle;
|
err = ::android::hardware::readEmbeddedFromParcel(
|
const_cast<hidl_vec<T> &>(*vec),
|
*parcel, parentHandle,
|
0 /* parentOffset */,
|
&childHandle);
|
|
for (size_t i = 0; (err == OK) && (i < vec->size()); i++) {
|
err = android::hardware::readEmbeddedFromParcel(
|
const_cast<T &>((*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<hidl_string> *vec = ReadHidlVector<hidl_string>(env, thiz);
|
return MakeStringArray(env, &(*vec)[0], vec->size());
|
}
|
|
static jobjectArray JHwParcel_native_readNativeHandleVector(
|
JNIEnv *env, jobject thiz) {
|
const hidl_vec<hidl_handle> *vec = ReadHidlVector<hidl_handle>(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<hardware::IBinder> 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<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 },
|
|
{ "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
|