From 0619b33685064da8c971456f971658eaa97d4d6c Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Mon, 15 Aug 2016 09:25:02 -0700 Subject: [PATCH 1/6] Initial commit of Java support for hardware binder (DO NOT MERGE) Change-Id: If1098ab921a11bae8eca2a70a3c3070e4daa0ea2 --- core/java/android/os/HwBinder.java | 59 ++ core/java/android/os/HwParcel.java | 120 +++ core/java/android/os/HwRemoteBinder.java | 56 ++ core/java/android/os/IHwBinder.java | 28 + core/java/android/os/IHwInterface.java | 22 + core/jni/Android.mk | 7 +- core/jni/AndroidRuntime.cpp | 6 + core/jni/android_os_HwBinder.cpp | 288 +++++++ core/jni/android_os_HwBinder.h | 60 ++ core/jni/android_os_HwParcel.cpp | 913 +++++++++++++++++++++++ core/jni/android_os_HwParcel.h | 75 ++ core/jni/android_os_HwRemoteBinder.cpp | 196 +++++ core/jni/android_os_HwRemoteBinder.h | 60 ++ core/jni/hwbinder/EphemeralStorage.cpp | 178 +++++ core/jni/hwbinder/EphemeralStorage.h | 84 +++ 15 files changed, 2151 insertions(+), 1 deletion(-) create mode 100644 core/java/android/os/HwBinder.java create mode 100644 core/java/android/os/HwParcel.java create mode 100644 core/java/android/os/HwRemoteBinder.java create mode 100644 core/java/android/os/IHwBinder.java create mode 100644 core/java/android/os/IHwInterface.java create mode 100644 core/jni/android_os_HwBinder.cpp create mode 100644 core/jni/android_os_HwBinder.h create mode 100644 core/jni/android_os_HwParcel.cpp create mode 100644 core/jni/android_os_HwParcel.h create mode 100644 core/jni/android_os_HwRemoteBinder.cpp create mode 100644 core/jni/android_os_HwRemoteBinder.h create mode 100644 core/jni/hwbinder/EphemeralStorage.cpp create mode 100644 core/jni/hwbinder/EphemeralStorage.h diff --git a/core/java/android/os/HwBinder.java b/core/java/android/os/HwBinder.java new file mode 100644 index 0000000000000..5ff79f752c394 --- /dev/null +++ b/core/java/android/os/HwBinder.java @@ -0,0 +1,59 @@ +/* + * 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. + */ + +package android.os; + +import libcore.util.NativeAllocationRegistry; + +/** @hide */ +public abstract class HwBinder implements IHwBinder { + private static final String TAG = "HwBinder"; + + private static final NativeAllocationRegistry sNativeRegistry; + + public HwBinder() { + native_setup(); + + sNativeRegistry.registerNativeAllocation( + this, + mNativeContext); + } + + public final native void transact( + int code, HwParcel request, HwParcel reply, int flags); + + public abstract void onTransact( + int code, HwParcel request, HwParcel reply, int flags); + + public native final void registerService(String serviceName); + public static native final IHwBinder getService(String serviceName); + + // Returns address of the "freeFunction". + private static native final long native_init(); + + private native final void native_setup(); + + static { + long freeFunction = native_init(); + + sNativeRegistry = new NativeAllocationRegistry( + HwBinder.class.getClassLoader(), + freeFunction, + 128 /* size */); + } + + private long mNativeContext; +} diff --git a/core/java/android/os/HwParcel.java b/core/java/android/os/HwParcel.java new file mode 100644 index 0000000000000..fe7cdccd3e097 --- /dev/null +++ b/core/java/android/os/HwParcel.java @@ -0,0 +1,120 @@ +/* + * 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. + */ + +package android.os; + +import libcore.util.NativeAllocationRegistry; + +/** @hide */ +public class HwParcel { + private static final String TAG = "HwParcel"; + + public static final int STATUS_SUCCESS = 0; + public static final int STATUS_ERROR = -1; + + private static final NativeAllocationRegistry sNativeRegistry; + + private HwParcel(boolean allocate) { + native_setup(allocate); + + sNativeRegistry.registerNativeAllocation( + this, + mNativeContext); + } + + public HwParcel() { + native_setup(true /* allocate */); + + sNativeRegistry.registerNativeAllocation( + this, + mNativeContext); + } + + public native final void writeInterfaceToken(String interfaceName); + public native final void writeInt8(byte val); + public native final void writeInt16(short val); + public native final void writeInt32(int val); + public native final void writeInt64(long val); + public native final void writeFloat(float val); + public native final void writeDouble(double val); + public native final void writeString(String val); + + public native final void writeInt8Array(int size, byte[] val); + public native final void writeInt8Vector(byte[] val); + public native final void writeInt16Array(int size, short[] val); + public native final void writeInt16Vector(short[] val); + public native final void writeInt32Array(int size, int[] val); + public native final void writeInt32Vector(int[] val); + public native final void writeInt64Array(int size, long[] val); + public native final void writeInt64Vector(long[] val); + public native final void writeFloatArray(int size, float[] val); + public native final void writeFloatVector(float[] val); + public native final void writeDoubleArray(int size, double[] val); + public native final void writeDoubleVector(double[] val); + public native final void writeStringArray(int size, String[] val); + public native final void writeStringVector(String[] val); + + public native final void writeStrongBinder(IHwBinder binder); + + public native final void enforceInterface(String interfaceName); + public native final byte readInt8(); + public native final short readInt16(); + public native final int readInt32(); + public native final long readInt64(); + public native final float readFloat(); + public native final double readDouble(); + public native final String readString(); + + public native final byte[] readInt8Array(int size); + public native final byte[] readInt8Vector(); + public native final short[] readInt16Array(int size); + public native final short[] readInt16Vector(); + public native final int[] readInt32Array(int size); + public native final int[] readInt32Vector(); + public native final long[] readInt64Array(int size); + public native final long[] readInt64Vector(); + public native final float[] readFloatArray(int size); + public native final float[] readFloatVector(); + public native final double[] readDoubleArray(int size); + public native final double[] readDoubleVector(); + public native final String[] readStringArray(int size); + public native final String[] readStringVector(); + + public native final IHwBinder readStrongBinder(); + + public native final void writeStatus(int status); + public native final void verifySuccess(); + public native final void releaseTemporaryStorage(); + + public native final void send(); + + // Returns address of the "freeFunction". + private static native final long native_init(); + + private native final void native_setup(boolean allocate); + + static { + long freeFunction = native_init(); + + sNativeRegistry = new NativeAllocationRegistry( + HwParcel.class.getClassLoader(), + freeFunction, + 128 /* size */); + } + + private long mNativeContext; +} + diff --git a/core/java/android/os/HwRemoteBinder.java b/core/java/android/os/HwRemoteBinder.java new file mode 100644 index 0000000000000..83866b3cceb75 --- /dev/null +++ b/core/java/android/os/HwRemoteBinder.java @@ -0,0 +1,56 @@ +/* + * 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. + */ + +package android.os; + +import libcore.util.NativeAllocationRegistry; + +/** @hide */ +public class HwRemoteBinder implements IHwBinder { + private static final String TAG = "HwRemoteBinder"; + + private static final NativeAllocationRegistry sNativeRegistry; + + public HwRemoteBinder() { + native_setup_empty(); + + sNativeRegistry.registerNativeAllocation( + this, + mNativeContext); + } + + public IHwInterface queryLocalInterface(String descriptor) { + return null; + } + + public native final void transact( + int code, HwParcel request, HwParcel reply, int flags); + + private static native final long native_init(); + + private native final void native_setup_empty(); + + static { + long freeFunction = native_init(); + + sNativeRegistry = new NativeAllocationRegistry( + HwRemoteBinder.class.getClassLoader(), + freeFunction, + 128 /* size */); + } + + private long mNativeContext; +} diff --git a/core/java/android/os/IHwBinder.java b/core/java/android/os/IHwBinder.java new file mode 100644 index 0000000000000..88af4fb137107 --- /dev/null +++ b/core/java/android/os/IHwBinder.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +package android.os; + +/** @hide */ +public interface IHwBinder { + // MUST match libhwbinder/IBinder.h definition !!! + public static final int FIRST_CALL_TRANSACTION = 1; + + public void transact( + int code, HwParcel request, HwParcel reply, int flags); + + public IHwInterface queryLocalInterface(String descriptor); +} diff --git a/core/java/android/os/IHwInterface.java b/core/java/android/os/IHwInterface.java new file mode 100644 index 0000000000000..7c5ac6f44a492 --- /dev/null +++ b/core/java/android/os/IHwInterface.java @@ -0,0 +1,22 @@ +/* + * 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. + */ + +package android.os; + +/** @hide */ +public interface IHwInterface { + public IHwBinder asBinder(); +} diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 60e888d17fc06..8175bf67135a2 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -80,6 +80,9 @@ LOCAL_SRC_FILES:= \ android_text_AndroidBidi.cpp \ android_text_StaticLayout.cpp \ android_os_Debug.cpp \ + android_os_HwBinder.cpp \ + android_os_HwParcel.cpp \ + android_os_HwRemoteBinder.cpp \ android_os_MemoryFile.cpp \ android_os_MessageQueue.cpp \ android_os_Parcel.cpp \ @@ -177,7 +180,8 @@ LOCAL_SRC_FILES:= \ com_android_internal_os_PathClassLoaderFactory.cpp \ com_android_internal_os_Zygote.cpp \ com_android_internal_util_VirtualRefBasePtr.cpp \ - com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp + com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp \ + hwbinder/EphemeralStorage.cpp \ LOCAL_C_INCLUDES += \ $(JNI_H_INCLUDE) \ @@ -260,6 +264,7 @@ LOCAL_SHARED_LIBRARIES := \ libradio_metadata \ libnativeloader \ libmemunreachable \ + libhwbinder \ LOCAL_SHARED_LIBRARIES += \ libhwui \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 6cbc06cd88473..109d3fbcd8475 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -156,6 +156,9 @@ extern int register_android_database_SQLiteGlobal(JNIEnv* env); extern int register_android_database_SQLiteDebug(JNIEnv* env); 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_HwParcel(JNIEnv *env); +extern int register_android_os_HwRemoteBinder(JNIEnv *env); extern int register_android_os_MessageQueue(JNIEnv* env); extern int register_android_os_Parcel(JNIEnv* env); extern int register_android_os_SELinux(JNIEnv* env); @@ -1287,6 +1290,9 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_os_SystemProperties), REG_JNI(register_android_os_Binder), REG_JNI(register_android_os_Parcel), + REG_JNI(register_android_os_HwBinder), + REG_JNI(register_android_os_HwParcel), + REG_JNI(register_android_os_HwRemoteBinder), REG_JNI(register_android_nio_utils), REG_JNI(register_android_graphics_Canvas), REG_JNI(register_android_graphics_Graphics), diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp new file mode 100644 index 0000000000000..a45e1eef2e8f8 --- /dev/null +++ b/core/jni/android_os_HwBinder.cpp @@ -0,0 +1,288 @@ +/* + * 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_HwBinder" +#include + +#include "android_os_HwBinder.h" + +#include "android_os_HwParcel.h" +#include "android_os_HwRemoteBinder.h" + +#include +#include +#include +#include +#include +#include + +#include "core_jni_helpers.h" + +using android::AndroidRuntime; + +#define PACKAGE_PATH "android/os" +#define CLASS_NAME "HwBinder" +#define CLASS_PATH PACKAGE_PATH "/" CLASS_NAME + +namespace android { + +static struct fields_t { + jfieldID contextID; + jmethodID onTransactID; + +} gFields; + +// static +void JHwBinder::InitClass(JNIEnv *env) { + ScopedLocalRef clazz( + env, FindClassOrDie(env, CLASS_PATH)); + + gFields.contextID = + GetFieldIDOrDie(env, clazz.get(), "mNativeContext", "J"); + + gFields.onTransactID = + GetMethodIDOrDie( + env, + clazz.get(), + "onTransact", + "(IL" PACKAGE_PATH "/HwParcel;L" PACKAGE_PATH "/HwParcel;I)V"); +} + +// static +sp JHwBinder::SetNativeContext( + JNIEnv *env, jobject thiz, const sp &context) { + sp old = + (JHwBinder *)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 JHwBinder::GetNativeContext( + JNIEnv *env, jobject thiz) { + return (JHwBinder *)env->GetLongField(thiz, gFields.contextID); +} + +JHwBinder::JHwBinder(JNIEnv *env, jobject thiz) { + jclass clazz = env->GetObjectClass(thiz); + CHECK(clazz != NULL); + + mClass = (jclass)env->NewGlobalRef(clazz); + mObject = env->NewWeakGlobalRef(thiz); +} + +JHwBinder::~JHwBinder() { + JNIEnv *env = AndroidRuntime::getJNIEnv(); + + env->DeleteWeakGlobalRef(mObject); + mObject = NULL; + + env->DeleteGlobalRef(mClass); + mClass = NULL; +} + +status_t JHwBinder::onTransact( + uint32_t code, + const hardware::Parcel &data, + hardware::Parcel *reply, + uint32_t flags, + TransactCallback callback) { + JNIEnv *env = AndroidRuntime::getJNIEnv(); + + ScopedLocalRef requestObj(env, JHwParcel::NewObject(env)); + JHwParcel::GetNativeContext(env, requestObj.get())->setParcel( + const_cast(&data), false /* assumeOwnership */); + + ScopedLocalRef replyObj(env, JHwParcel::NewObject(env)); + + sp replyContext = + JHwParcel::GetNativeContext(env, replyObj.get()); + + replyContext->setParcel(reply, false /* assumeOwnership */); + replyContext->setTransactCallback(callback); + + env->CallVoidMethod( + mObject, + gFields.onTransactID, + code, + requestObj.get(), + replyObj.get(), + flags); + + status_t err = OK; + + if (!replyContext->wasSent()) { + // The implementation never finished the transaction. + err = UNKNOWN_ERROR; // XXX special error code instead? + + reply->setDataPosition(0 /* pos */); + } + + // Release all temporary storage now that scatter-gather data + // has been consolidated, either by calling the TransactCallback, + // if wasSent() == true or clearing the reply parcel (setDataOffset above). + replyContext->getStorage()->release(env); + + // We cannot permanently pass ownership of "data" and "reply" over to their + // Java object wrappers (we don't own them ourselves). + + JHwParcel::GetNativeContext(env, requestObj.get())->setParcel( + NULL /* parcel */, false /* assumeOwnership */); + + replyContext->setParcel( + NULL /* parcel */, false /* assumeOwnership */); + + return err; +} + +} // namespace android + +//////////////////////////////////////////////////////////////////////////////// + +using namespace android; + +static void releaseNativeContext(void *nativeContext) { + sp binder = (JHwBinder *)nativeContext; + + if (binder != NULL) { + binder->decStrong(NULL /* id */); + } +} + +static jlong JHwBinder_native_init(JNIEnv *env) { + JHwBinder::InitClass(env); + + return reinterpret_cast(&releaseNativeContext); +} + +static void JHwBinder_native_setup(JNIEnv *env, jobject thiz) { + sp context = new JHwBinder(env, thiz); + + JHwBinder::SetNativeContext(env, thiz, context); +} + +static void JHwBinder_native_transact( + JNIEnv * /* env */, + jobject /* thiz */, + jint /* code */, + jobject /* requestObj */, + jobject /* replyObj */, + jint /* flags */) { + CHECK(!"Should not be here"); +} + +static void JHwBinder_native_registerService( + JNIEnv *env, jobject thiz, jstring serviceNameObj) { + if (serviceNameObj == NULL) { + jniThrowException(env, "java/lang/NullPointerException", NULL); + return; + } + + const jchar *serviceName = env->GetStringCritical(serviceNameObj, NULL); + + if (serviceName == NULL) { + return; // XXX exception already pending? + } + + const hardware::hidl_version kVersion = hardware::make_hidl_version(1, 0); + + sp binder = JHwBinder::GetNativeContext(env, thiz); + + status_t err = hardware::defaultServiceManager()->addService( + String16(reinterpret_cast(serviceName)), + binder, + kVersion); + + env->ReleaseStringCritical(serviceNameObj, serviceName); + serviceName = NULL; + + if (err == OK) { + LOG(INFO) << "Starting thread pool."; + ::android::hardware::ProcessState::self()->startThreadPool(); + } + + signalExceptionForError(env, err); +} + +static jobject JHwBinder_native_getService( + JNIEnv *env, jclass /* clazzObj */, jstring serviceNameObj) { + if (serviceNameObj == NULL) { + jniThrowException(env, "java/lang/NullPointerException", NULL); + return NULL; + } + + const jchar *serviceName = env->GetStringCritical(serviceNameObj, NULL); + + if (serviceName == NULL) { + return NULL; // XXX exception already pending? + } + + const hardware::hidl_version kVersion = hardware::make_hidl_version(1, 0); + + LOG(INFO) << "looking for service '" + << String8(String16( + reinterpret_cast(serviceName))).string() + << "'"; + + sp service = + hardware::defaultServiceManager()->getService( + String16(reinterpret_cast(serviceName)), + kVersion); + + env->ReleaseStringCritical(serviceNameObj, serviceName); + serviceName = NULL; + + if (service == NULL) { + signalExceptionForError(env, NAME_NOT_FOUND); + return NULL; + } + + return JHwRemoteBinder::NewObject(env, service); +} + +static JNINativeMethod gMethods[] = { + { "native_init", "()J", (void *)JHwBinder_native_init }, + { "native_setup", "()V", (void *)JHwBinder_native_setup }, + + { "transact", + "(IL" PACKAGE_PATH "/HwParcel;L" PACKAGE_PATH "/HwParcel;I)V", + (void *)JHwBinder_native_transact }, + + { "registerService", "(Ljava/lang/String;)V", + (void *)JHwBinder_native_registerService }, + + { "getService", "(Ljava/lang/String;)L" PACKAGE_PATH "/IHwBinder;", + (void *)JHwBinder_native_getService }, +}; + +namespace android { + +int register_android_os_HwBinder(JNIEnv *env) { + return RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods)); +} + +} // namespace android diff --git a/core/jni/android_os_HwBinder.h b/core/jni/android_os_HwBinder.h new file mode 100644 index 0000000000000..2ebc38164da80 --- /dev/null +++ b/core/jni/android_os_HwBinder.h @@ -0,0 +1,60 @@ +/* + * 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_BINDER_H +#define _ANDROID_OS_HW_BINDER_H + +#include +#include +#include +#include + +namespace android { + +struct JHwBinder : public hardware::BBinder { + static void InitClass(JNIEnv *env); + + static sp SetNativeContext( + JNIEnv *env, jobject thiz, const sp &context); + + static sp GetNativeContext(JNIEnv *env, jobject thiz); + + JHwBinder(JNIEnv *env, jobject thiz); + +protected: + virtual ~JHwBinder(); + + virtual status_t onTransact( + uint32_t code, + const hardware::Parcel &data, + hardware::Parcel *reply, + uint32_t flags, + TransactCallback callback); + +private: + jclass mClass; + jobject mObject; + + DISALLOW_COPY_AND_ASSIGN(JHwBinder); +}; + +int register_android_os_HwBinder(JNIEnv *env); + +} // namespace android + +#endif // _ANDROID_OS_HW_BINDER_H + + diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp new file mode 100644 index 0000000000000..0202303b10ea2 --- /dev/null +++ b/core/jni/android_os_HwParcel.cpp @@ -0,0 +1,913 @@ +/* + * 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_HwRemoteBinder.h" + +#include +#include +#include +#include + +#include "core_jni_helpers.h" + +using android::AndroidRuntime; + +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) { + 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 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: + { + jniThrowException( + env, "java/lang/RuntimeException", "Unknown error"); + + 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) { + jclass clazz = env->GetObjectClass(thiz); + CHECK(clazz != NULL); + + mClass = (jclass)env->NewGlobalRef(clazz); + mObject = env->NewWeakGlobalRef(thiz); +} + +JHwParcel::~JHwParcel() { + JNIEnv *env = AndroidRuntime::getJNIEnv(); + + mStorage.release(env); + + setParcel(NULL, false /* assumeOwnership */); + + env->DeleteWeakGlobalRef(mObject); + mObject = NULL; + + env->DeleteGlobalRef(mClass); + mClass = NULL; +} + +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)); + + return env->NewObject( + clazz.get(), gFields.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) { + hardware::Parcel *parcel = + JHwParcel::GetNativeContext(env, thiz)->getParcel(); + + status_t err = parcel->writeInterfaceToken( + String16( + reinterpret_cast(interfaceName), + env->GetStringLength(interfaceNameObj))); + + env->ReleaseStringCritical(interfaceNameObj, interfaceName); + interfaceName = NULL; + + 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) { + hardware::Parcel *parcel = + JHwParcel::GetNativeContext(env, thiz)->getParcel(); + + bool valid = parcel->enforceInterface( + String16( + reinterpret_cast(interfaceName), + env->GetStringLength(interfaceNameObj))); + + env->ReleaseStringCritical(interfaceNameObj, interfaceName); + interfaceName = NULL; + + 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(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 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 = status.writeToParcel(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 = status.readFromParcel(*parcel); + signalExceptionForError(env, err); +} + +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 = s->writeEmbeddedToParcel( + parcel, parentHandle, 0 /* parentOffset */); + } + + signalExceptionForError(env, err); +} + +#define DEFINE_PARCEL_ARRAY_WRITER(Suffix,Type) \ +static void JHwParcel_native_write ## Suffix ## Array( \ + JNIEnv *env, jobject thiz, jint size, Type ## Array valObj) { \ + if (valObj == NULL) { \ + jniThrowException(env, "java/lang/NullPointerException", NULL); \ + return; \ + } \ + \ + jsize len = env->GetArrayLength(valObj); \ + \ + if (len != size) { \ + jniThrowException(env, "java/lang/IllegalArgumentException", NULL); \ + return; \ + } \ + \ + sp impl = JHwParcel::GetNativeContext(env, thiz); \ + \ + const Type *val = \ + impl->getStorage()->allocTemporary ## Suffix ## Array(env, valObj); \ + \ + hardware::Parcel *parcel = impl->getParcel(); \ + \ + size_t parentHandle; \ + status_t err = parcel->writeBuffer( \ + val, size * sizeof(*val), &parentHandle); \ + \ + 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 = vec->writeEmbeddedToParcel( \ + parcel, \ + parentHandle, \ + 0 /* parentOffset */, \ + &childHandle); \ + } \ + \ + signalExceptionForError(env, err); \ +} + +DEFINE_PARCEL_ARRAY_WRITER(Int8,jbyte) +DEFINE_PARCEL_ARRAY_WRITER(Int16,jshort) +DEFINE_PARCEL_ARRAY_WRITER(Int32,jint) +DEFINE_PARCEL_ARRAY_WRITER(Int64,jlong) +DEFINE_PARCEL_ARRAY_WRITER(Float,jfloat) +DEFINE_PARCEL_ARRAY_WRITER(Double,jdouble) + +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_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::GetNativeContext(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 = static_cast( + parcel->readBuffer(&parentHandle)); + + if (s == NULL) { + signalExceptionForError(env, UNKNOWN_ERROR); + return NULL; + } + + status_t err = const_cast(s)->readEmbeddedFromParcel( + *parcel, parentHandle, 0 /* parentOffset */); + + if (err != OK) { + signalExceptionForError(env, err); + return NULL; + } + + return MakeStringObjFromHidlString(env, *s); +} + +#define DEFINE_PARCEL_ARRAY_READER(Suffix,Type,NewType) \ +static Type ## Array JHwParcel_native_read ## Suffix ## Array( \ + JNIEnv *env, jobject thiz, jint size) { \ + hardware::Parcel *parcel = \ + JHwParcel::GetNativeContext(env, thiz)->getParcel(); \ + \ + size_t parentHandle; \ + const Type *val = static_cast( \ + parcel->readBuffer(&parentHandle)); \ + \ + Type ## Array valObj = env->New ## NewType ## Array(size); \ + env->Set ## NewType ## ArrayRegion(valObj, 0, size, val); \ + \ + return valObj; \ +} + +#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 = \ + (const hidl_vec *)parcel->readBuffer(&parentHandle); \ + \ + if (vec == NULL) { \ + signalExceptionForError(env, UNKNOWN_ERROR); \ + return NULL; \ + } \ + \ + size_t childHandle; \ + \ + status_t err = const_cast *>(vec) \ + ->readEmbeddedFromParcel( \ + *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_ARRAY_READER(Int8,jbyte,Byte) +DEFINE_PARCEL_ARRAY_READER(Int16,jshort,Short) +DEFINE_PARCEL_ARRAY_READER(Int32,jint,Int) +DEFINE_PARCEL_ARRAY_READER(Int64,jlong,Long) +DEFINE_PARCEL_ARRAY_READER(Float,jfloat,Float) +DEFINE_PARCEL_ARRAY_READER(Double,jdouble,Double) + +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 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; +} + +static jobjectArray JHwParcel_native_readStringArray( + JNIEnv *env, jobject thiz, jint size) { + hardware::Parcel *parcel = + JHwParcel::GetNativeContext(env, thiz)->getParcel(); + + size_t parentHandle; + const hidl_string *val = static_cast( + parcel->readBuffer(&parentHandle)); + + if (val == NULL) { + signalExceptionForError(env, UNKNOWN_ERROR); + return NULL; + } + + status_t err = OK; + for (jint i = 0; (err == OK) && (i < size); ++i) { + err = const_cast(&val[i]) + ->readEmbeddedFromParcel( + *parcel, + parentHandle, + i * sizeof(hidl_string)); + } + + if (err != OK) { + signalExceptionForError(env, err); + return NULL; + } + + return MakeStringArray(env, val, size); +} + +static void JHwParcel_native_writeStringArray( + JNIEnv *env, jobject thiz, jint size, jobjectArray arrayObj) { + if (arrayObj == NULL) { + jniThrowException(env, "java/lang/NullPointerException", NULL); + return; + } + + jsize len = env->GetArrayLength(arrayObj); + + if (len != size) { + jniThrowException(env, "java/lang/IllegalArgumentException", NULL); + return; + } + + sp impl = JHwParcel::GetNativeContext(env, thiz); + + hidl_string *strings = impl->getStorage()->allocStringArray(len); + + for (jsize i = 0; i < len; ++i) { + ScopedLocalRef stringObj( + env, + (jstring)env->GetObjectArrayElement(arrayObj, i)); + + const hidl_string *s = + impl->getStorage()->allocTemporaryString(env, stringObj.get()); + + strings[i].setToExternal(s->c_str(), s->size()); + } + + hardware::Parcel *parcel = impl->getParcel(); + + size_t parentHandle; + status_t err = parcel->writeBuffer( + strings, sizeof(hidl_string) * len, &parentHandle); + + for (jsize i = 0; (err == OK) && (i < len); ++i) { + err = strings[i].writeEmbeddedToParcel( + parcel, parentHandle, i * sizeof(hidl_string)); + } + + signalExceptionForError(env, err); +} + +static jobjectArray JHwParcel_native_readStringVector( + JNIEnv *env, jobject thiz) { + typedef hidl_vec string_vec; + + hardware::Parcel *parcel = + JHwParcel::GetNativeContext(env, thiz)->getParcel(); + + size_t parentHandle; + + const string_vec *vec= + (const string_vec *)parcel->readBuffer(&parentHandle); + + if (vec == NULL) { + signalExceptionForError(env, UNKNOWN_ERROR); + return NULL; + } + + size_t childHandle; + status_t err = const_cast(vec)->readEmbeddedFromParcel( + *parcel, parentHandle, 0 /* parentOffset */, &childHandle); + + for (size_t i = 0; (err == OK) && (i < vec->size()); ++i) { + err = const_cast *>(vec) + ->readEmbeddedFromParcel( + *parcel, + childHandle, + i * sizeof(hidl_string), + nullptr /* childHandle */); + } + + if (err != OK) { + signalExceptionForError(env, err); + return NULL; + } + + return MakeStringArray(env, &(*vec)[0], vec->size()); +} + +static void JHwParcel_native_writeStringVector( + JNIEnv *env, jobject thiz, jobjectArray arrayObj) { + typedef hidl_vec string_vec; + + if (arrayObj == NULL) { + jniThrowException(env, "java/lang/NullPointerException", NULL); + return; + } + + jsize len = env->GetArrayLength(arrayObj); + + sp impl = JHwParcel::GetNativeContext(env, thiz); + + string_vec *vec = + (string_vec *)impl->getStorage()->allocTemporaryStorage( + sizeof(string_vec)); + + hidl_string *strings = impl->getStorage()->allocStringArray(len); + vec->setToExternal(strings, len); + + for (jsize i = 0; i < len; ++i) { + ScopedLocalRef stringObj( + env, + (jstring)env->GetObjectArrayElement(arrayObj, i)); + + const hidl_string *s = + impl->getStorage()->allocTemporaryString(env, stringObj.get()); + + strings[i].setToExternal(s->c_str(), s->size()); + } + + hardware::Parcel *parcel = impl->getParcel(); + + size_t parentHandle; + status_t err = parcel->writeBuffer(vec, sizeof(*vec), &parentHandle); + + if (err == OK) { + size_t childHandle; + err = vec->writeEmbeddedToParcel( + parcel, + parentHandle, + 0 /* parentOffset */, + &childHandle); + + for (size_t i = 0; (err == OK) && (i < vec->size()); ++i) { + err = (*vec)[i].writeEmbeddedToParcel( + parcel, + childHandle, + i * sizeof(hidl_string)); + } + } + + signalExceptionForError(env, err); +} + +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 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 }, + + { "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 }, + + { "writeInt8Array", "(I[B)V", (void *)JHwParcel_native_writeInt8Array }, + { "writeInt8Vector", "([B)V", (void *)JHwParcel_native_writeInt8Vector }, + { "writeInt16Array", "(I[S)V", (void *)JHwParcel_native_writeInt16Array }, + { "writeInt16Vector", "([S)V", (void *)JHwParcel_native_writeInt16Vector }, + { "writeInt32Array", "(I[I)V", (void *)JHwParcel_native_writeInt32Array }, + { "writeInt32Vector", "([I)V", (void *)JHwParcel_native_writeInt32Vector }, + { "writeInt64Array", "(I[J)V", (void *)JHwParcel_native_writeInt64Array }, + { "writeInt64Vector", "([J)V", (void *)JHwParcel_native_writeInt64Vector }, + { "writeFloatArray", "(I[F)V", (void *)JHwParcel_native_writeFloatArray }, + { "writeFloatVector", "([F)V", (void *)JHwParcel_native_writeFloatVector }, + { "writeDoubleArray", "(I[D)V", (void *)JHwParcel_native_writeDoubleArray }, + + { "writeDoubleVector", "([D)V", + (void *)JHwParcel_native_writeDoubleVector }, + + { "writeStringArray", "(I[Ljava/lang/String;)V", + (void *)JHwParcel_native_writeStringArray }, + + { "writeStringVector", "([Ljava/lang/String;)V", + (void *)JHwParcel_native_writeStringVector }, + + { "writeStrongBinder", "(L" PACKAGE_PATH "/IHwBinder;)V", + (void *)JHwParcel_native_writeStrongBinder }, + + { "enforceInterface", "(Ljava/lang/String;)V", + (void *)JHwParcel_native_enforceInterface }, + + { "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 }, + + { "readInt8Array", "(I)[B", (void *)JHwParcel_native_readInt8Array }, + { "readInt8Vector", "()[B", (void *)JHwParcel_native_readInt8Vector }, + { "readInt16Array", "(I)[S", (void *)JHwParcel_native_readInt16Array }, + { "readInt16Vector", "()[S", (void *)JHwParcel_native_readInt16Vector }, + { "readInt32Array", "(I)[I", (void *)JHwParcel_native_readInt32Array }, + { "readInt32Vector", "()[I", (void *)JHwParcel_native_readInt32Vector }, + { "readInt64Array", "(I)[J", (void *)JHwParcel_native_readInt64Array }, + { "readInt64Vector", "()[J", (void *)JHwParcel_native_readInt64Vector }, + { "readFloatArray", "(I)[F", (void *)JHwParcel_native_readFloatArray }, + { "readFloatVector", "()[F", (void *)JHwParcel_native_readFloatVector }, + { "readDoubleArray", "(I)[D", (void *)JHwParcel_native_readDoubleArray }, + { "readDoubleVector", "()[D", (void *)JHwParcel_native_readDoubleVector }, + + { "readStringArray", "(I)[Ljava/lang/String;", + (void *)JHwParcel_native_readStringArray }, + + { "readStringVector", "()[Ljava/lang/String;", + (void *)JHwParcel_native_readStringVector }, + + { "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 }, +}; + +namespace android { + +int register_android_os_HwParcel(JNIEnv *env) { + return RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods)); +} + +} // namespace android diff --git a/core/jni/android_os_HwParcel.h b/core/jni/android_os_HwParcel.h new file mode 100644 index 0000000000000..708bbba1901ce --- /dev/null +++ b/core/jni/android_os_HwParcel.h @@ -0,0 +1,75 @@ +/* + * 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_PARCEL_H +#define ANDROID_OS_HW_PARCEL_H + +#include "hwbinder/EphemeralStorage.h" + +#include +#include +#include +#include +#include + +namespace android { + +struct JHwParcel : public RefBase { + static void InitClass(JNIEnv *env); + + static sp SetNativeContext( + JNIEnv *env, jobject thiz, const sp &context); + + static sp GetNativeContext(JNIEnv *env, jobject thiz); + + static jobject NewObject(JNIEnv *env); + + JHwParcel(JNIEnv *env, jobject thiz); + + void setParcel(hardware::Parcel *parcel, bool assumeOwnership); + hardware::Parcel *getParcel(); + + EphemeralStorage *getStorage(); + + void setTransactCallback(::android::hardware::IBinder::TransactCallback cb); + + void send(); + bool wasSent() const; + +protected: + virtual ~JHwParcel(); + +private: + jclass mClass; + jobject mObject; + + hardware::Parcel *mParcel; + bool mOwnsParcel; + + EphemeralStorage mStorage; + + ::android::hardware::IBinder::TransactCallback mTransactCallback; + bool mWasSent; + + DISALLOW_COPY_AND_ASSIGN(JHwParcel); +}; + +void signalExceptionForError(JNIEnv *env, status_t err); +int register_android_os_HwParcel(JNIEnv *env); + +} // namespace android + +#endif // ANDROID_OS_HW_PARCEL_H diff --git a/core/jni/android_os_HwRemoteBinder.cpp b/core/jni/android_os_HwRemoteBinder.cpp new file mode 100644 index 0000000000000..23d4fced21830 --- /dev/null +++ b/core/jni/android_os_HwRemoteBinder.cpp @@ -0,0 +1,196 @@ +/* + * 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 "JHwRemoteBinder" +#include + +#include "android_os_HwRemoteBinder.h" + +#include "android_os_HwParcel.h" + +#include +#include +#include +#include +#include + +#include "core_jni_helpers.h" + +using android::AndroidRuntime; + +#define PACKAGE_PATH "android/os" +#define CLASS_NAME "HwRemoteBinder" +#define CLASS_PATH PACKAGE_PATH "/" CLASS_NAME + +namespace android { + +static struct fields_t { + jfieldID contextID; + jmethodID constructID; + +} gFields; + +// static +void JHwRemoteBinder::InitClass(JNIEnv *env) { + ScopedLocalRef clazz(env, FindClassOrDie(env, CLASS_PATH)); + + gFields.contextID = + GetFieldIDOrDie(env, clazz.get(), "mNativeContext", "J"); + + gFields.constructID = GetMethodIDOrDie(env, clazz.get(), "", "()V"); +} + +// static +sp JHwRemoteBinder::SetNativeContext( + JNIEnv *env, jobject thiz, const sp &context) { + sp old = + (JHwRemoteBinder *)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 JHwRemoteBinder::GetNativeContext( + JNIEnv *env, jobject thiz) { + return (JHwRemoteBinder *)env->GetLongField(thiz, gFields.contextID); +} + +// static +jobject JHwRemoteBinder::NewObject( + JNIEnv *env, const sp &binder) { + ScopedLocalRef clazz(env, FindClassOrDie(env, CLASS_PATH)); + + // XXX Have to look up the constructor here because otherwise that static + // class initializer isn't called and gFields.constructID is undefined :( + + jmethodID constructID = GetMethodIDOrDie(env, clazz.get(), "", "()V"); + + jobject obj = env->NewObject(clazz.get(), constructID); + JHwRemoteBinder::GetNativeContext(env, obj)->setBinder(binder); + + return obj; +} + +JHwRemoteBinder::JHwRemoteBinder( + JNIEnv *env, jobject thiz, const sp &binder) + : mBinder(binder) { + jclass clazz = env->GetObjectClass(thiz); + CHECK(clazz != NULL); + + mClass = (jclass)env->NewGlobalRef(clazz); + mObject = env->NewWeakGlobalRef(thiz); +} + +JHwRemoteBinder::~JHwRemoteBinder() { + JNIEnv *env = AndroidRuntime::getJNIEnv(); + + env->DeleteWeakGlobalRef(mObject); + mObject = NULL; + + env->DeleteGlobalRef(mClass); + mClass = NULL; +} + +sp JHwRemoteBinder::getBinder() { + return mBinder; +} + +void JHwRemoteBinder::setBinder(const sp &binder) { + mBinder = binder; +} + +} // namespace android + +//////////////////////////////////////////////////////////////////////////////// + +using namespace android; + +static void releaseNativeContext(void *nativeContext) { + sp binder = (JHwRemoteBinder *)nativeContext; + + if (binder != NULL) { + binder->decStrong(NULL /* id */); + } +} + +static jlong JHwRemoteBinder_native_init(JNIEnv *env) { + JHwRemoteBinder::InitClass(env); + + return reinterpret_cast(&releaseNativeContext); +} + +static void JHwRemoteBinder_native_setup_empty(JNIEnv *env, jobject thiz) { + sp context = + new JHwRemoteBinder(env, thiz, NULL /* service */); + + JHwRemoteBinder::SetNativeContext(env, thiz, context); +} + +static void JHwRemoteBinder_native_transact( + JNIEnv *env, + jobject thiz, + jint code, + jobject requestObj, + jobject replyObj, + jint flags) { + sp binder = + JHwRemoteBinder::GetNativeContext(env, thiz)->getBinder(); + + if (requestObj == NULL) { + jniThrowException(env, "java/lang/NullPointerException", NULL); + return; + } + + const hardware::Parcel *request = + JHwParcel::GetNativeContext(env, requestObj)->getParcel(); + + hardware::Parcel *reply = + JHwParcel::GetNativeContext(env, replyObj)->getParcel(); + + status_t err = binder->transact(code, *request, reply, flags); + signalExceptionForError(env, err); +} + +static JNINativeMethod gMethods[] = { + { "native_init", "()J", (void *)JHwRemoteBinder_native_init }, + + { "native_setup_empty", "()V", + (void *)JHwRemoteBinder_native_setup_empty }, + + { "transact", + "(IL" PACKAGE_PATH "/HwParcel;L" PACKAGE_PATH "/HwParcel;I)V", + (void *)JHwRemoteBinder_native_transact }, +}; + +namespace android { + +int register_android_os_HwRemoteBinder(JNIEnv *env) { + return RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods)); +} + +} // namespace android + diff --git a/core/jni/android_os_HwRemoteBinder.h b/core/jni/android_os_HwRemoteBinder.h new file mode 100644 index 0000000000000..fd33338986a03 --- /dev/null +++ b/core/jni/android_os_HwRemoteBinder.h @@ -0,0 +1,60 @@ +/* + * 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_REMOTE_BINDER_H +#define ANDROID_OS_HW_REMOTE_BINDER_H + +#include +#include +#include +#include + +namespace android { + +struct JHwRemoteBinder : public RefBase { + static void InitClass(JNIEnv *env); + + static sp SetNativeContext( + JNIEnv *env, jobject thiz, const sp &context); + + static sp GetNativeContext(JNIEnv *env, jobject thiz); + + static jobject NewObject(JNIEnv *env, const sp &binder); + + JHwRemoteBinder( + JNIEnv *env, jobject thiz, const sp &binder); + + sp getBinder(); + void setBinder(const sp &binder); + +protected: + virtual ~JHwRemoteBinder(); + +private: + jclass mClass; + jobject mObject; + + sp mBinder; + + DISALLOW_COPY_AND_ASSIGN(JHwRemoteBinder); +}; + +int register_android_os_HwRemoteBinder(JNIEnv *env); + +} // namespace android + +#endif // ANDROID_OS_HW_REMOTE_BINDER_H + diff --git a/core/jni/hwbinder/EphemeralStorage.cpp b/core/jni/hwbinder/EphemeralStorage.cpp new file mode 100644 index 0000000000000..e5087081ba55d --- /dev/null +++ b/core/jni/hwbinder/EphemeralStorage.cpp @@ -0,0 +1,178 @@ +/* + * 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_TAG "EphemeralStorage" +//#define LOG_NDEBUG 0 + +#include + +#include "EphemeralStorage.h" + +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; + +namespace android { + +EphemeralStorage::EphemeralStorage() { +} + +EphemeralStorage::~EphemeralStorage() { + CHECK(mItems.empty()) + << "All item storage should have been released by now."; +} + +hidl_string *EphemeralStorage::allocStringArray(size_t size) { + Item item; + item.mType = TYPE_STRING_ARRAY; + item.mObj = NULL; + item.mPtr = new hidl_string[size]; + mItems.push_back(item); + + return static_cast(item.mPtr); +} + +void *EphemeralStorage::allocTemporaryStorage(size_t size) { + Item item; + item.mType = TYPE_STORAGE; + item.mObj = NULL; + item.mPtr = malloc(size); + mItems.push_back(item); + + return item.mPtr; +} + +const hidl_string *EphemeralStorage::allocTemporaryString( + JNIEnv *env, jstring stringObj) { + jstring obj = (jstring)env->NewGlobalRef(stringObj); + const char *val = env->GetStringUTFChars(obj, NULL); + + Item item; + item.mType = TYPE_STRING; + item.mObj = obj; + item.mPtr = (void *)val; + mItems.push_back(item); + + hidl_string *s = allocStringArray(1 /* size */); + s->setToExternal((char *)val, strlen(val)); + + return s; +} + +#define DEFINE_ALLOC_ARRAY_METHODS(Suffix,Type,NewType) \ +const Type *EphemeralStorage::allocTemporary ## Suffix ## Array( \ + JNIEnv *env, Type ## Array arrayObj) { \ + Type ## Array obj = (Type ## Array)env->NewGlobalRef(arrayObj); \ + const Type *val = env->Get ## NewType ## ArrayElements(obj, NULL); \ + \ + Item item; \ + item.mType = TYPE_ ## Suffix ## _ARRAY; \ + item.mObj = obj; \ + item.mPtr = (void *)val; \ + mItems.push_back(item); \ + \ + return val; \ +} + +#define DEFINE_ALLOC_VECTOR_METHODS(Suffix,Type,NewType) \ +const hidl_vec *EphemeralStorage::allocTemporary ## Suffix ## Vector( \ + JNIEnv *env, Type ## Array arrayObj) { \ + Type ## Array obj = (Type ## Array)env->NewGlobalRef(arrayObj); \ + jsize len = env->GetArrayLength(obj); \ + const Type *val = env->Get ## NewType ## ArrayElements(obj, NULL); \ + \ + Item item; \ + item.mType = TYPE_ ## Suffix ## _ARRAY; \ + item.mObj = obj; \ + item.mPtr = (void *)val; \ + mItems.push_back(item); \ + \ + hidl_vec *vec = \ + (hidl_vec *)allocTemporaryStorage(sizeof(hidl_vec)); \ + \ + vec->setToExternal(const_cast(val), len); \ + \ + return vec; \ +} + +DEFINE_ALLOC_ARRAY_METHODS(Int8,jbyte,Byte) +DEFINE_ALLOC_ARRAY_METHODS(Int16,jshort,Short) +DEFINE_ALLOC_ARRAY_METHODS(Int32,jint,Int) +DEFINE_ALLOC_ARRAY_METHODS(Int64,jlong,Long) +DEFINE_ALLOC_ARRAY_METHODS(Float,jfloat,Float) +DEFINE_ALLOC_ARRAY_METHODS(Double,jdouble,Double) + +DEFINE_ALLOC_VECTOR_METHODS(Int8,jbyte,Byte) +DEFINE_ALLOC_VECTOR_METHODS(Int16,jshort,Short) +DEFINE_ALLOC_VECTOR_METHODS(Int32,jint,Int) +DEFINE_ALLOC_VECTOR_METHODS(Int64,jlong,Long) +DEFINE_ALLOC_VECTOR_METHODS(Float,jfloat,Float) +DEFINE_ALLOC_VECTOR_METHODS(Double,jdouble,Double) + +#define DEFINE_RELEASE_ARRAY_CASE(Suffix,Type,NewType) \ + case TYPE_ ## Suffix ## _ARRAY: \ + { \ + env->Release ## NewType ## ArrayElements( \ + (Type ## Array)item.mObj, \ + (Type *)item.mPtr, \ + 0 /* mode */); \ + \ + env->DeleteGlobalRef(item.mObj); \ + break; \ + } + +void EphemeralStorage::release(JNIEnv *env) { + for (size_t i = mItems.size(); i--;) { + const Item &item = mItems[i]; + + switch (item.mType) { + case TYPE_STRING_ARRAY: + { + delete[] static_cast(item.mPtr); + break; + } + + case TYPE_STORAGE: + { + free(item.mPtr); + break; + } + + case TYPE_STRING: + { + env->ReleaseStringUTFChars( + (jstring)item.mObj, (const char *)item.mPtr); + + env->DeleteGlobalRef(item.mObj); + break; + } + + DEFINE_RELEASE_ARRAY_CASE(Int8,jbyte,Byte) + DEFINE_RELEASE_ARRAY_CASE(Int16,jshort,Short) + DEFINE_RELEASE_ARRAY_CASE(Int32,jint,Int) + DEFINE_RELEASE_ARRAY_CASE(Int64,jlong,Long) + DEFINE_RELEASE_ARRAY_CASE(Float,jfloat,Float) + DEFINE_RELEASE_ARRAY_CASE(Double,jdouble,Double) + + default: + CHECK(!"Should not be here"); + } + } + + mItems.clear(); +} + +} // namespace android + diff --git a/core/jni/hwbinder/EphemeralStorage.h b/core/jni/hwbinder/EphemeralStorage.h new file mode 100644 index 0000000000000..1273003e61765 --- /dev/null +++ b/core/jni/hwbinder/EphemeralStorage.h @@ -0,0 +1,84 @@ +/* + * 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 EPHEMERAL_STORAGE_H_ + +#define EPHEMERAL_STORAGE_H_ + +#include +#include +#include +#include + +namespace android { + +#define DECLARE_ALLOC_METHODS(Suffix,Type) \ + const Type *allocTemporary ## Suffix ## Array( \ + JNIEnv *env, Type ## Array arrayObj); \ + \ + const ::android::hardware::hidl_vec * \ + allocTemporary ## Suffix ## Vector( \ + JNIEnv *env, Type ## Array arrayObj); + +struct EphemeralStorage { + EphemeralStorage(); + ~EphemeralStorage(); + + void release(JNIEnv *env); + + hardware::hidl_string *allocStringArray(size_t size); + + void *allocTemporaryStorage(size_t size); + + const ::android::hardware::hidl_string *allocTemporaryString( + JNIEnv *env, jstring stringObj); + + DECLARE_ALLOC_METHODS(Int8,jbyte) + DECLARE_ALLOC_METHODS(Int16,jshort) + DECLARE_ALLOC_METHODS(Int32,jint) + DECLARE_ALLOC_METHODS(Int64,jlong) + DECLARE_ALLOC_METHODS(Float,jfloat) + DECLARE_ALLOC_METHODS(Double,jdouble) + +private: + enum Type { + TYPE_STRING_ARRAY, + TYPE_STORAGE, + TYPE_STRING, + TYPE_Int8_ARRAY, + TYPE_Int16_ARRAY, + TYPE_Int32_ARRAY, + TYPE_Int64_ARRAY, + TYPE_Float_ARRAY, + TYPE_Double_ARRAY, + }; + + struct Item { + Type mType; + jobject mObj; + void *mPtr; + }; + + Vector mItems; + + DISALLOW_COPY_AND_ASSIGN(EphemeralStorage); +}; + +#undef DECLARE_ALLOC_METHODS + +} // namespace android + +#endif // EPHEMERAL_STORAGE_H_ From ea2ae56e035928345cd5f98095cff907c8ddea14 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Thu, 18 Aug 2016 14:29:40 -0700 Subject: [PATCH 2/6] Support one-way methods in java support for hardware binder (DO NOT MERGE) Bug: 30922538 Change-Id: I5ff93126a29f6bff42dee3f9868fa794ca7c077f Signed-off-by: Iliyan Malchev --- core/java/android/os/IHwBinder.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/java/android/os/IHwBinder.java b/core/java/android/os/IHwBinder.java index 88af4fb137107..76e881eda8af4 100644 --- a/core/java/android/os/IHwBinder.java +++ b/core/java/android/os/IHwBinder.java @@ -18,8 +18,9 @@ package android.os; /** @hide */ public interface IHwBinder { - // MUST match libhwbinder/IBinder.h definition !!! + // These MUST match their corresponding libhwbinder/IBinder.h definition !!! public static final int FIRST_CALL_TRANSACTION = 1; + public static final int FLAG_ONEWAY = 1; public void transact( int code, HwParcel request, HwParcel reply, int flags); From 83c42506a73e4e52f452836a43db2f4bc5555ec5 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Fri, 19 Aug 2016 14:23:42 +0200 Subject: [PATCH 3/6] Link against libhidl for HidlSupport/svcmgr (DO NOT MERGE) Bug: 30839546 Change-Id: I52609576aa7f10da608725ef4ea78b778f127eef Signed-off-by: Iliyan Malchev --- core/jni/Android.mk | 1 + core/jni/android_os_HwBinder.cpp | 2 +- core/jni/android_os_HwRemoteBinder.cpp | 2 +- core/jni/hwbinder/EphemeralStorage.h | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 8175bf67135a2..08be2eb126e0b 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -264,6 +264,7 @@ LOCAL_SHARED_LIBRARIES := \ libradio_metadata \ libnativeloader \ libmemunreachable \ + libhidl \ libhwbinder \ LOCAL_SHARED_LIBRARIES += \ diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp index a45e1eef2e8f8..132ed95046561 100644 --- a/core/jni/android_os_HwBinder.cpp +++ b/core/jni/android_os_HwBinder.cpp @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include #include diff --git a/core/jni/android_os_HwRemoteBinder.cpp b/core/jni/android_os_HwRemoteBinder.cpp index 23d4fced21830..81ba368d67434 100644 --- a/core/jni/android_os_HwRemoteBinder.cpp +++ b/core/jni/android_os_HwRemoteBinder.cpp @@ -24,7 +24,7 @@ #include #include -#include +#include #include #include diff --git a/core/jni/hwbinder/EphemeralStorage.h b/core/jni/hwbinder/EphemeralStorage.h index 1273003e61765..b02ed9f5ea69a 100644 --- a/core/jni/hwbinder/EphemeralStorage.h +++ b/core/jni/hwbinder/EphemeralStorage.h @@ -19,7 +19,7 @@ #define EPHEMERAL_STORAGE_H_ #include -#include +#include #include #include From 52073b842f24d5638cc815a5da5863fdde6d0b96 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Wed, 24 Aug 2016 16:19:03 -0700 Subject: [PATCH 4/6] Add Bool* APIs to HwParcel (DO NOT MERGE) Bug: 31045584 Change-Id: I202c4aa7caf92a4cd7e3a45ef6784638e41facc8 Signed-off-by: Iliyan Malchev --- core/java/android/os/HwParcel.java | 6 ++ core/jni/android_os_HwParcel.cpp | 160 +++++++++++++++++++++++++++++ 2 files changed, 166 insertions(+) diff --git a/core/java/android/os/HwParcel.java b/core/java/android/os/HwParcel.java index fe7cdccd3e097..52579e53fbb19 100644 --- a/core/java/android/os/HwParcel.java +++ b/core/java/android/os/HwParcel.java @@ -44,6 +44,7 @@ public class HwParcel { } public native final void writeInterfaceToken(String interfaceName); + public native final void writeBool(boolean val); public native final void writeInt8(byte val); public native final void writeInt16(short val); public native final void writeInt32(int val); @@ -52,6 +53,8 @@ public class HwParcel { public native final void writeDouble(double val); public native final void writeString(String val); + public native final void writeBoolArray(int size, boolean[] val); + public native final void writeBoolVector(boolean[] val); public native final void writeInt8Array(int size, byte[] val); public native final void writeInt8Vector(byte[] val); public native final void writeInt16Array(int size, short[] val); @@ -70,6 +73,7 @@ public class HwParcel { public native final void writeStrongBinder(IHwBinder binder); public native final void enforceInterface(String interfaceName); + public native final boolean readBool(); public native final byte readInt8(); public native final short readInt16(); public native final int readInt32(); @@ -78,6 +82,8 @@ public class HwParcel { public native final double readDouble(); public native final String readString(); + public native final boolean[] readBoolArray(int size); + public native final boolean[] readBoolVector(); public native final byte[] readInt8Array(int size); public native final byte[] readInt8Vector(); public native final short[] readInt16Array(int size); diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp index 0202303b10ea2..94918f69a2ffe 100644 --- a/core/jni/android_os_HwParcel.cpp +++ b/core/jni/android_os_HwParcel.cpp @@ -333,6 +333,7 @@ static Type JHwParcel_native_read ## Suffix( \ return val; \ } +DEFINE_PARCEL_WRITER(Bool,jboolean) DEFINE_PARCEL_WRITER(Int8,jbyte) DEFINE_PARCEL_WRITER(Int16,jshort) DEFINE_PARCEL_WRITER(Int32,jint) @@ -347,6 +348,17 @@ 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; @@ -489,6 +501,90 @@ DEFINE_PARCEL_VECTOR_WRITER(Int64,jlong) DEFINE_PARCEL_VECTOR_WRITER(Float,jfloat) DEFINE_PARCEL_VECTOR_WRITER(Double,jdouble) +static void JHwParcel_native_writeBoolArray( + JNIEnv *env, jobject thiz, jint size, jbooleanArray valObj) { + if (valObj == NULL) { + jniThrowException(env, "java/lang/NullPointerException", NULL); + return; + } + + jsize len = env->GetArrayLength(valObj); + + if (len != size) { + jniThrowException(env, "java/lang/IllegalArgumentException", NULL); + return; + } + + sp impl = JHwParcel::GetNativeContext(env, thiz); + + jboolean *src = env->GetBooleanArrayElements(valObj, nullptr); + + bool *dst = + (bool *)impl->getStorage()->allocTemporaryStorage(size * sizeof(bool)); + + for (jint i = 0; i < size; ++i) { + dst[i] = src[i]; + } + + env->ReleaseBooleanArrayElements(valObj, src, 0 /* mode */); + src = nullptr; + + hardware::Parcel *parcel = impl->getParcel(); + + size_t parentHandle; + status_t err = parcel->writeBuffer( + dst, size * sizeof(*dst), &parentHandle); + + signalExceptionForError(env, err); +} + +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); + + hidl_vec *vec = + (hidl_vec *)impl->getStorage()->allocTemporaryStorage( + sizeof(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 = vec->writeEmbeddedToParcel( + parcel, + parentHandle, + 0 /* parentOffset */, + &childHandle); + } + + signalExceptionForError(env, err); +} + static void JHwParcel_native_writeStrongBinder( JNIEnv *env, jobject thiz, jobject binderObj) { sp binder; @@ -616,6 +712,64 @@ 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_readBoolArray( + JNIEnv *env, jobject thiz, jint size) { + hardware::Parcel *parcel = + JHwParcel::GetNativeContext(env, thiz)->getParcel(); + + size_t parentHandle; + const bool *val = static_cast( + parcel->readBuffer(&parentHandle)); + + jbooleanArray valObj = env->NewBooleanArray(size); + + for (jint i = 0; i < size; ++i) { + jboolean x = val[i]; + env->SetBooleanArrayRegion(valObj, i, 1, &x); + } + + return valObj; +} + +static jbooleanArray JHwParcel_native_readBoolVector( + JNIEnv *env, jobject thiz) { + hardware::Parcel *parcel = + JHwParcel::GetNativeContext(env, thiz)->getParcel(); + + size_t parentHandle; + + const hidl_vec *vec = + (const hidl_vec *)parcel->readBuffer(&parentHandle); + + if (vec == NULL) { + signalExceptionForError(env, UNKNOWN_ERROR); + return NULL; + } + + size_t childHandle; + + status_t err = const_cast *>(vec) + ->readEmbeddedFromParcel( + *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( @@ -825,6 +979,7 @@ static JNINativeMethod gMethods[] = { { "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 }, @@ -835,6 +990,8 @@ static JNINativeMethod gMethods[] = { { "writeString", "(Ljava/lang/String;)V", (void *)JHwParcel_native_writeString }, + { "writeBoolArray", "(I[Z)V", (void *)JHwParcel_native_writeBoolArray }, + { "writeBoolVector", "([Z)V", (void *)JHwParcel_native_writeBoolVector }, { "writeInt8Array", "(I[B)V", (void *)JHwParcel_native_writeInt8Array }, { "writeInt8Vector", "([B)V", (void *)JHwParcel_native_writeInt8Vector }, { "writeInt16Array", "(I[S)V", (void *)JHwParcel_native_writeInt16Array }, @@ -862,6 +1019,7 @@ static JNINativeMethod gMethods[] = { { "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 }, @@ -872,6 +1030,8 @@ static JNINativeMethod gMethods[] = { { "readString", "()Ljava/lang/String;", (void *)JHwParcel_native_readString }, + { "readBoolArray", "(I)[Z", (void *)JHwParcel_native_readBoolArray }, + { "readBoolVector", "()[Z", (void *)JHwParcel_native_readBoolVector }, { "readInt8Array", "(I)[B", (void *)JHwParcel_native_readInt8Array }, { "readInt8Vector", "()[B", (void *)JHwParcel_native_readInt8Vector }, { "readInt16Array", "(I)[S", (void *)JHwParcel_native_readInt16Array }, From 54e4578e604865391b4e2fe52597626976b070c2 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Thu, 25 Aug 2016 11:21:21 -0700 Subject: [PATCH 5/6] Adds framework support for hidl-gen Java backend. (to support structs) (DO NOT MERGE) Bug: 30575790 Change-Id: Ida30d8fe7a1b210e98f1a0ea5d429a0112f9ef3f Signed-off-by: Iliyan Malchev --- core/java/android/os/HwBlob.java | 74 ++++ core/java/android/os/HwParcel.java | 8 + core/jni/Android.mk | 1 + core/jni/AndroidRuntime.cpp | 2 + core/jni/android_os_HwBlob.cpp | 452 +++++++++++++++++++++++++ core/jni/android_os_HwBlob.h | 91 +++++ core/jni/android_os_HwParcel.cpp | 82 ++++- core/jni/hwbinder/EphemeralStorage.cpp | 4 +- 8 files changed, 704 insertions(+), 10 deletions(-) create mode 100644 core/java/android/os/HwBlob.java create mode 100644 core/jni/android_os_HwBlob.cpp create mode 100644 core/jni/android_os_HwBlob.h diff --git a/core/java/android/os/HwBlob.java b/core/java/android/os/HwBlob.java new file mode 100644 index 0000000000000..153c6e634ecbf --- /dev/null +++ b/core/java/android/os/HwBlob.java @@ -0,0 +1,74 @@ +/* + * 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. + */ + +package android.os; + +import libcore.util.NativeAllocationRegistry; + +/** @hide */ +public class HwBlob { + private static final String TAG = "HwBlob"; + + private static final NativeAllocationRegistry sNativeRegistry; + + public HwBlob(int size) { + native_setup(size); + + sNativeRegistry.registerNativeAllocation( + this, + mNativeContext); + } + + public native final boolean getBool(long offset); + public native final byte getInt8(long offset); + public native final short getInt16(long offset); + public native final int getInt32(long offset); + public native final long getInt64(long offset); + public native final float getFloat(long offset); + public native final double getDouble(long offset); + public native final String getString(long offset); + + public native final void putBool(long offset, boolean x); + public native final void putInt8(long offset, byte x); + public native final void putInt16(long offset, short x); + public native final void putInt32(long offset, int x); + public native final void putInt64(long offset, long x); + public native final void putFloat(long offset, float x); + public native final void putDouble(long offset, double x); + public native final void putString(long offset, String x); + + public native final void putBlob(long offset, HwBlob blob); + + public native final long handle(); + + // Returns address of the "freeFunction". + private static native final long native_init(); + + private native final void native_setup(int size); + + static { + long freeFunction = native_init(); + + sNativeRegistry = new NativeAllocationRegistry( + HwBlob.class.getClassLoader(), + freeFunction, + 128 /* size */); + } + + private long mNativeContext; +} + + diff --git a/core/java/android/os/HwParcel.java b/core/java/android/os/HwParcel.java index 52579e53fbb19..e4d57184ede9f 100644 --- a/core/java/android/os/HwParcel.java +++ b/core/java/android/os/HwParcel.java @@ -101,6 +101,14 @@ public class HwParcel { public native final IHwBinder readStrongBinder(); + // Handle is stored as part of the blob. + public native final HwBlob readBuffer(); + + public native final HwBlob readEmbeddedBuffer( + long parentHandle, long offset); + + public native final void writeBuffer(HwBlob blob); + public native final void writeStatus(int status); public native final void verifySuccess(); public native final void releaseTemporaryStorage(); diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 08be2eb126e0b..7e1a0ab064577 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -81,6 +81,7 @@ LOCAL_SRC_FILES:= \ 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 109d3fbcd8475..07392c4055d32 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -157,6 +157,7 @@ extern int register_android_database_SQLiteDebug(JNIEnv* env); 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 @@ static const RegJNIRec gRegJNI[] = { 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 0000000000000..6972cf1209699 --- /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 + +#include "android_os_HwBlob.h" + +#include "android_os_HwParcel.h" + +#include +#include +#include +#include + +#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 clazz( + env, FindClassOrDie(env, CLASS_PATH)); + + gFields.contextID = + GetFieldIDOrDie(env, clazz.get(), "mNativeContext", "J"); + + gFields.constructID = GetMethodIDOrDie(env, clazz.get(), "", "(I)V"); +} + +// static +sp JHwBlob::SetNativeContext( + JNIEnv *env, jobject thiz, const sp &context) { + sp 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::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(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 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 &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 clazz(env, FindClassOrDie(env, CLASS_PATH)); + + jmethodID constructID = + GetMethodIDOrDie(env, clazz.get(), "", "(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 parcel = (JHwBlob *)nativeContext; + + if (parcel != NULL) { + parcel->decStrong(NULL /* id */); + } +} + +static jlong JHwBlob_native_init(JNIEnv *env) { + JHwBlob::InitClass(env); + + return reinterpret_cast(&releaseNativeContext); +} + +static void JHwBlob_native_setup( + JNIEnv *env, jobject thiz, jint size) { + sp 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 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 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 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 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 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 subBlobObj(env, JHwBlob::NewObject(env, size)); + sp 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(subBlob->data()), size); + + sp 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 blob = JHwBlob::GetNativeContext(env, thiz); + sp 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 0000000000000..6bd82e98e9118 --- /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 +#include +#include +#include +#include + +namespace android { + +struct JHwBlob : public RefBase { + static void InitClass(JNIEnv *env); + + static sp SetNativeContext( + JNIEnv *env, jobject thiz, const sp &context); + + static sp 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 &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 mBlob; + }; + + jclass mClass; + jobject mObject; + + void *mBuffer; + size_t mSize; + bool mOwnsBuffer; + + size_t mHandle; + + Vector 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 94918f69a2ffe..226d61ba57f36 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 @@ -71,6 +72,7 @@ void signalExceptionForError(JNIEnv *env, status_t err) { break; } + case -ERANGE: case BAD_INDEX: { jniThrowException(env, "java/lang/IndexOutOfBoundsException", NULL); @@ -200,8 +202,10 @@ void JHwParcel::setParcel(hardware::Parcel *parcel, bool assumeOwnership) { jobject JHwParcel::NewObject(JNIEnv *env) { ScopedLocalRef clazz(env, FindClassOrDie(env, CLASS_PATH)); - return env->NewObject( - clazz.get(), gFields.constructID, false /* allocate */); + jmethodID constructID = + GetMethodIDOrDie(env, clazz.get(), "", "(Z)V"); + + return env->NewObject(clazz.get(), constructID, false /* allocate */); } void JHwParcel::setTransactCallback( @@ -547,9 +551,10 @@ static void JHwParcel_native_writeBoolVector( sp impl = JHwParcel::GetNativeContext(env, thiz); - hidl_vec *vec = - (hidl_vec *)impl->getStorage()->allocTemporaryStorage( - sizeof(hidl_vec)); + void *vecPtr = + impl->getStorage()->allocTemporaryStorage(sizeof(hidl_vec)); + + hidl_vec *vec = new (vecPtr) hidl_vec; jsize len = env->GetArrayLength(valObj); @@ -917,9 +922,10 @@ static void JHwParcel_native_writeStringVector( sp 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 @@ static jobject JHwParcel_native_readStrongBinder(JNIEnv *env, jobject thiz) { 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 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 @@ static JNINativeMethod gMethods[] = { (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 e5087081ba55d..187beeea4de1e 100644 --- a/core/jni/hwbinder/EphemeralStorage.cpp +++ b/core/jni/hwbinder/EphemeralStorage.cpp @@ -99,9 +99,9 @@ const hidl_vec *EphemeralStorage::allocTemporary ## Suffix ## Vector( \ item.mPtr = (void *)val; \ mItems.push_back(item); \ \ - hidl_vec *vec = \ - (hidl_vec *)allocTemporaryStorage(sizeof(hidl_vec)); \ + void *vecPtr = allocTemporaryStorage(sizeof(hidl_vec)); \ \ + hidl_vec *vec = new (vecPtr) hidl_vec; \ vec->setToExternal(const_cast(val), len); \ \ return vec; \ From d713c4c39e321eb06c32d7afce38bb81a760db5a Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Thu, 1 Sep 2016 01:37:05 +0200 Subject: [PATCH 6/6] Move Status to libhidl (DO NOT MERGE) Bug: 31226252 Change-Id: Ieb0adcf1fa71d6859324c2d83841685d1e1a22f8 Signed-off-by: Iliyan Malchev --- core/jni/android_os_HwBinder.cpp | 2 +- core/jni/android_os_HwBlob.cpp | 2 +- core/jni/android_os_HwParcel.cpp | 2 +- core/jni/android_os_HwRemoteBinder.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp index 132ed95046561..97833a078f4cc 100644 --- a/core/jni/android_os_HwBinder.cpp +++ b/core/jni/android_os_HwBinder.cpp @@ -26,8 +26,8 @@ #include #include #include +#include #include -#include #include #include "core_jni_helpers.h" diff --git a/core/jni/android_os_HwBlob.cpp b/core/jni/android_os_HwBlob.cpp index 6972cf1209699..b2dee0689ee0c 100644 --- a/core/jni/android_os_HwBlob.cpp +++ b/core/jni/android_os_HwBlob.cpp @@ -24,7 +24,7 @@ #include #include -#include +#include #include #include "core_jni_helpers.h" diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp index 226d61ba57f36..d453b29c0663e 100644 --- a/core/jni/android_os_HwParcel.cpp +++ b/core/jni/android_os_HwParcel.cpp @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include "core_jni_helpers.h" diff --git a/core/jni/android_os_HwRemoteBinder.cpp b/core/jni/android_os_HwRemoteBinder.cpp index 81ba368d67434..3023ba87d24b0 100644 --- a/core/jni/android_os_HwRemoteBinder.cpp +++ b/core/jni/android_os_HwRemoteBinder.cpp @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include "core_jni_helpers.h"