Merge "Implementing support for HIDL native handles in Java"

am: 1e1d8d2485

Change-Id: I5f2f709bcb87174850140e5ca7d4296338c1f56f
This commit is contained in:
Steven Moreland
2018-08-14 09:54:46 -07:00
committed by android-build-merger
14 changed files with 726 additions and 106 deletions

View File

@@ -898,6 +898,7 @@ java_library {
"core/java/android/os/IHwInterface.java",
"core/java/android/os/DeadObjectException.java",
"core/java/android/os/DeadSystemException.java",
"core/java/android/os/NativeHandle.java",
"core/java/android/os/RemoteException.java",
"core/java/android/util/AndroidException.java",
],
@@ -1444,6 +1445,7 @@ droiddoc {
"core/java/android/os/IHwInterface.java",
"core/java/android/os/DeadObjectException.java",
"core/java/android/os/DeadSystemException.java",
"core/java/android/os/NativeHandle.java",
"core/java/android/os/RemoteException.java",
"core/java/android/util/AndroidException.java",
],

View File

@@ -3726,6 +3726,7 @@ package android.os {
method public final void putInt64Array(long, long[]);
method public final void putInt8(long, byte);
method public final void putInt8Array(long, byte[]);
method public final void putNativeHandle(long, android.os.NativeHandle);
method public final void putString(long, java.lang.String);
method public static java.lang.Boolean[] wrapArray(boolean[]);
method public static java.lang.Long[] wrapArray(long[]);
@@ -3745,6 +3746,7 @@ package android.os {
method public final double readDouble();
method public final java.util.ArrayList<java.lang.Double> readDoubleVector();
method public final android.os.HwBlob readEmbeddedBuffer(long, long, long, boolean);
method public final android.os.NativeHandle readEmbeddedNativeHandle(long, long);
method public final float readFloat();
method public final java.util.ArrayList<java.lang.Float> readFloatVector();
method public final short readInt16();
@@ -3755,6 +3757,8 @@ package android.os {
method public final java.util.ArrayList<java.lang.Long> readInt64Vector();
method public final byte readInt8();
method public final java.util.ArrayList<java.lang.Byte> readInt8Vector();
method public final android.os.NativeHandle readNativeHandle();
method public final java.util.ArrayList<android.os.NativeHandle> readNativeHandleVector();
method public final java.lang.String readString();
method public final java.util.ArrayList<java.lang.String> readStringVector();
method public final android.os.IHwBinder readStrongBinder();
@@ -3778,6 +3782,8 @@ package android.os {
method public final void writeInt8(byte);
method public final void writeInt8Vector(java.util.ArrayList<java.lang.Byte>);
method public final void writeInterfaceToken(java.lang.String);
method public final void writeNativeHandle(android.os.NativeHandle);
method public final void writeNativeHandleVector(java.util.ArrayList<android.os.NativeHandle>);
method public final void writeStatus(int);
method public final void writeString(java.lang.String);
method public final void writeStringVector(java.util.ArrayList<java.lang.String>);
@@ -3822,6 +3828,18 @@ package android.os {
field public static final android.os.Parcelable.Creator<android.os.IncidentReportArgs> CREATOR;
}
public final class NativeHandle implements java.io.Closeable {
ctor public NativeHandle();
ctor public NativeHandle(java.io.FileDescriptor, boolean);
ctor public NativeHandle(java.io.FileDescriptor[], int[], boolean);
method public void close() throws java.io.IOException;
method public android.os.NativeHandle dup() throws java.io.IOException;
method public java.io.FileDescriptor getFileDescriptor();
method public java.io.FileDescriptor[] getFileDescriptors();
method public int[] getInts();
method public boolean hasSingleFileDescriptor();
}
public final class PowerManager {
method public void userActivity(long, int, int);
field public static final int USER_ACTIVITY_EVENT_ACCESSIBILITY = 3; // 0x3

View File

@@ -232,6 +232,14 @@ public class HwBlob {
* @throws IndexOutOfBoundsException when [offset, offset + sizeof(jstring)] is out of range
*/
public native final void putString(long offset, String x);
/**
* Writes a native handle (without duplicating the underlying file descriptors) at an offset.
*
* @param offset location to write value
* @param x a {@link NativeHandle} instance to write
* @throws IndexOutOfBoundsException when [offset, offset + sizeof(jobject)] is out of range
*/
public native final void putNativeHandle(long offset, NativeHandle x);
/**
* Put a boolean array contiguously at an offset in the blob.

View File

@@ -115,6 +115,13 @@ public class HwParcel {
* @param val to write
*/
public native final void writeString(String val);
/**
* Writes a native handle (without duplicating the underlying
* file descriptors) to the end of the parcel.
*
* @param val to write
*/
public native final void writeNativeHandle(NativeHandle val);
/**
* Writes an array of boolean values to the end of the parcel.
@@ -159,6 +166,11 @@ public class HwParcel {
* @param val to write
*/
private native final void writeStringVector(String[] val);
/**
* Writes an array of native handles to the end of the parcel.
* @param val array of {@link NativeHandle} objects to write
*/
private native final void writeNativeHandleVector(NativeHandle[] val);
/**
* Helper method to write a list of Booleans to val.
@@ -266,6 +278,14 @@ public class HwParcel {
writeStringVector(val.toArray(new String[val.size()]));
}
/**
* Helper method to write a list of native handles to the end of the parcel.
* @param val list of {@link NativeHandle} objects to write
*/
public final void writeNativeHandleVector(ArrayList<NativeHandle> val) {
writeNativeHandleVector(val.toArray(new NativeHandle[val.size()]));
}
/**
* Write a hwbinder object to the end of the parcel.
* @param binder value to write
@@ -328,6 +348,30 @@ public class HwParcel {
* @throws IllegalArgumentException if the parcel has no more data
*/
public native final String readString();
/**
* Reads a native handle (without duplicating the underlying file
* descriptors) from the parcel. These file descriptors will only
* be open for the duration that the binder window is open. If they
* are needed further, you must call {@link NativeHandle#dup()}.
*
* @return a {@link NativeHandle} instance parsed from the parcel
* @throws IllegalArgumentException if the parcel has no more data
*/
public native final NativeHandle readNativeHandle();
/**
* Reads an embedded native handle (without duplicating the underlying
* file descriptors) from the parcel. These file descriptors will only
* be open for the duration that the binder window is open. If they
* are needed further, you must call {@link NativeHandle#dup()}. You
* do not need to call close on the NativeHandle returned from this.
*
* @param parentHandle handle from which to read the embedded object
* @param offset offset into parent
* @return a {@link NativeHandle} instance parsed from the parcel
* @throws IllegalArgumentException if the parcel has no more data
*/
public native final NativeHandle readEmbeddedNativeHandle(
long parentHandle, long offset);
/**
* Reads an array of boolean values from the parcel.
@@ -377,6 +421,12 @@ public class HwParcel {
* @throws IllegalArgumentException if the parcel has no more data
*/
private native final String[] readStringVectorAsArray();
/**
* Reads an array of native handles from the parcel.
* @return array of {@link NativeHandle} objects
* @throws IllegalArgumentException if the parcel has no more data
*/
private native final NativeHandle[] readNativeHandleAsArray();
/**
* Convenience method to read a Boolean vector as an ArrayList.
@@ -464,6 +514,15 @@ public class HwParcel {
return new ArrayList<String>(Arrays.asList(readStringVectorAsArray()));
}
/**
* Convenience method to read a vector of native handles as an ArrayList.
* @return array of {@link NativeHandle} objects.
* @throws IllegalArgumentException if the parcel has no more data
*/
public final ArrayList<NativeHandle> readNativeHandleVector() {
return new ArrayList<NativeHandle>(Arrays.asList(readNativeHandleAsArray()));
}
/**
* Reads a strong binder value from the parcel.
* @return binder object read from parcel or null if no binder can be read

View File

@@ -0,0 +1,191 @@
/*
* Copyright (C) 2018 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 android.annotation.NonNull;
import android.annotation.SystemApi;
import android.system.ErrnoException;
import android.system.Os;
import java.io.Closeable;
import java.io.FileDescriptor;
/**
* Collection representing a set of open file descriptors and an opaque data stream.
*
* @hide
*/
@SystemApi
public final class NativeHandle implements Closeable {
// whether this object owns mFds
private boolean mOwn = false;
private FileDescriptor[] mFds;
private int[] mInts;
/**
* Constructs a {@link NativeHandle} object containing
* zero file descriptors and an empty data stream.
*/
public NativeHandle() {
this(new FileDescriptor[0], new int[0], false);
}
/**
* Constructs a {@link NativeHandle} object containing the given
* {@link FileDescriptor} object and an empty data stream.
*/
public NativeHandle(@NonNull FileDescriptor descriptor, boolean own) {
this(new FileDescriptor[] {descriptor}, new int[0], own);
}
/**
* Convenience method for creating a list of file descriptors.
*
* @hide
*/
private static FileDescriptor[] createFileDescriptorArray(@NonNull int[] fds) {
FileDescriptor[] list = new FileDescriptor[fds.length];
for (int i = 0; i < fds.length; i++) {
FileDescriptor descriptor = new FileDescriptor();
descriptor.setInt$(fds[i]);
list[i] = descriptor;
}
return list;
}
/**
* Convenience method for instantiating a {@link NativeHandle} from JNI. It does
* not take ownership of the int[] params. It does not dupe the FileDescriptors.
*
* @hide
*/
private NativeHandle(@NonNull int[] fds, @NonNull int[] ints, boolean own) {
this(createFileDescriptorArray(fds), ints, own);
}
/**
* Instantiate an opaque {@link NativeHandle} from fds and integers.
*
* @param own whether the fds are owned by this object and should be closed
*/
public NativeHandle(@NonNull FileDescriptor[] fds, @NonNull int[] ints, boolean own) {
mFds = fds.clone();
mInts = ints.clone();
mOwn = own;
}
/**
* Returns whether this {@link NativeHandle} object contains a single file
* descriptor and nothing else.
*
* @return a boolean value
*/
public boolean hasSingleFileDescriptor() {
return mFds.length == 1 && mInts.length == 0;
}
/**
* Explicitly duplicate NativeHandle (this dups all file descritptors).
*/
public NativeHandle dup() throws java.io.IOException {
FileDescriptor[] fds = new FileDescriptor[mFds.length];
try {
for (int i = 0; i < mFds.length; i++) {
fds[i] = Os.dup(mFds[i]);
}
} catch (ErrnoException e) {
e.rethrowAsIOException();
}
return new NativeHandle(fds, mInts, true /*own*/);
}
/**
* Closes the file descriptors if they are owned by this object.
*
* This also invalidates the object.
*/
@Override
public void close() throws java.io.IOException {
if (!mOwn) {
return;
}
try {
for (FileDescriptor fd : mFds) {
Os.close(fd);
}
} catch (ErrnoException e) {
e.rethrowAsIOException();
}
mOwn = false;
mFds = null;
mInts = null;
}
/**
* Returns the underlying lone file descriptor.
*
* @return a {@link FileDescriptor} object
* @throws IllegalStateException if this object contains either zero or
* more than one file descriptor, or a non-empty data stream.
*/
public FileDescriptor getFileDescriptor() {
if (!hasSingleFileDescriptor()) {
throw new IllegalStateException(
"NativeHandle is not single file descriptor. Contents must"
+ " be retreived through getFileDescriptors and getInts.");
}
return mFds[0];
}
/**
* Convenience method for fetching this object's file descriptors from JNI.
* @return a mutable copy of the underlying file descriptors (as an int[])
*
* @hide
*/
private int[] getFdsAsIntArray() {
int numFds = mFds.length;
int[] fds = new int[numFds];
for (int i = 0; i < numFds; i++) {
fds[i] = mFds[i].getInt$();
}
return fds;
}
/**
* Fetch file descriptors.
*
* @return the fds.
*/
public FileDescriptor[] getFileDescriptors() {
return mFds;
}
/**
* Fetch opaque ints. Note: This object retains ownership of the data.
*
* @return the opaque data stream.
*/
public int[] getInts() {
return mInts;
}
}

View File

@@ -93,6 +93,7 @@ cc_library_shared {
"android_os_HwBlob.cpp",
"android_os_HwParcel.cpp",
"android_os_HwRemoteBinder.cpp",
"android_os_NativeHandle.cpp",
"android_os_MemoryFile.cpp",
"android_os_MessageQueue.cpp",
"android_os_Parcel.cpp",

View File

@@ -165,6 +165,7 @@ 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_NativeHandle(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);
@@ -1345,6 +1346,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_os_HwBlob),
REG_JNI(register_android_os_HwParcel),
REG_JNI(register_android_os_HwRemoteBinder),
REG_JNI(register_android_os_NativeHandle),
REG_JNI(register_android_os_VintfObject),
REG_JNI(register_android_os_VintfRuntimeInfo),
REG_JNI(register_android_nio_utils),

View File

@@ -21,6 +21,7 @@
#include "android_os_HwBlob.h"
#include "android_os_HwParcel.h"
#include "android_os_NativeHandle.h"
#include <nativehelper/JNIHelp.h>
#include <android_runtime/AndroidRuntime.h>
@@ -31,6 +32,7 @@
#include "core_jni_helpers.h"
using android::AndroidRuntime;
using android::hardware::hidl_handle;
using android::hardware::hidl_string;
#define PACKAGE_PATH "android/os"
@@ -82,6 +84,7 @@ sp<JHwBlob> JHwBlob::GetNativeContext(JNIEnv *env, jobject thiz) {
JHwBlob::JHwBlob(JNIEnv *env, jobject thiz, size_t size)
: mBuffer(nullptr),
mSize(size),
mType(BlobType::GENERIC),
mOwnsBuffer(true),
mHandle(0) {
if (size > 0) {
@@ -159,6 +162,15 @@ size_t JHwBlob::size() const {
return mSize;
}
void JHwBlob::specializeBlobTo(BlobType type) {
CHECK_EQ(static_cast<int>(mType), static_cast<int>(BlobType::GENERIC));
mType = type;
}
JHwBlob::BlobType JHwBlob::type() const {
return mType;
}
status_t JHwBlob::putBlob(size_t offset, const sp<JHwBlob> &blob) {
size_t index = mSubBlobs.add();
BlobInfo *info = &mSubBlobs.editItemAt(index);
@@ -172,42 +184,52 @@ status_t JHwBlob::putBlob(size_t offset, const sp<JHwBlob> &blob) {
}
status_t JHwBlob::writeToParcel(hardware::Parcel *parcel) const {
size_t handle;
CHECK_EQ(static_cast<int>(mType), static_cast<int>(BlobType::GENERIC));
size_t handle = 0;
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;
return writeSubBlobsToParcel(parcel, handle);
}
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);
size_t handle = 0;
status_t err = OK;
switch (mType) {
case BlobType::GENERIC: {
err = parcel->writeEmbeddedBuffer(data(), size(), &handle, parentHandle, parentOffset);
break;
}
case BlobType::NATIVE_HANDLE: {
err = parcel->writeEmbeddedNativeHandle(
static_cast<const native_handle *>(data()), parentHandle, parentOffset);
CHECK(mSubBlobs.empty());
break;
}
default: { err = INVALID_OPERATION; }
}
if (err != OK) {
return err;
}
return writeSubBlobsToParcel(parcel, handle);
}
status_t JHwBlob::writeSubBlobsToParcel(hardware::Parcel *parcel,
size_t parentHandle) const {
for (size_t i = 0; i < mSubBlobs.size(); ++i) {
const BlobInfo &info = mSubBlobs[i];
err = info.mBlob->writeEmbeddedToParcel(parcel, handle, info.mOffset);
status_t err = info.mBlob->writeEmbeddedToParcel(parcel, parentHandle, info.mOffset);
if (err != OK) {
return err;
@@ -252,7 +274,7 @@ static void releaseNativeContext(void *nativeContext) {
}
}
static jlong JHwBlob_native_init(JNIEnv *env) {
static jlong JHwBlob_native_init(JNIEnv *env, jclass /*clazz*/) {
JHwBlob::InitClass(env);
return reinterpret_cast<jlong>(&releaseNativeContext);
@@ -456,6 +478,31 @@ static void JHwBlob_native_putString(
blob->putBlob(offset + hidl_string::kOffsetOfBuffer, subBlob);
}
static void JHwBlob_native_putNativeHandle(JNIEnv *env, jobject thiz,
jlong offset, jobject jHandle) {
std::unique_ptr<native_handle_t, int(*)(native_handle_t*)> nativeHandle(
JNativeHandle::MakeCppNativeHandle(env, jHandle, nullptr /* storage */),
native_handle_delete);
size_t size = 0;
if (nativeHandle != nullptr) {
size = sizeof(native_handle_t) + nativeHandle->numFds * sizeof(int)
+ nativeHandle->numInts * sizeof(int);
}
ScopedLocalRef<jobject> subBlobObj(env, JHwBlob::NewObject(env, size));
sp<JHwBlob> subBlob = JHwBlob::GetNativeContext(env, subBlobObj.get());
subBlob->specializeBlobTo(JHwBlob::BlobType::NATIVE_HANDLE);
subBlob->write(0 /* offset */, nativeHandle.get(), size);
hidl_handle cppHandle;
cppHandle.setTo(static_cast<native_handle_t *>(subBlob->data()), false /* shouldOwn */);
sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
blob->write(offset, &cppHandle, sizeof(cppHandle));
blob->putBlob(offset + hidl_handle::kOffsetOfNativeHandle, subBlob);
}
#define DEFINE_BLOB_ARRAY_PUTTER(Suffix,Type,NewType) \
static void JHwBlob_native_put ## Suffix ## Array( \
JNIEnv *env, jobject thiz, jlong offset, Type ## Array array) { \
@@ -563,6 +610,8 @@ static JNINativeMethod gMethods[] = {
{ "putFloat", "(JF)V", (void *)JHwBlob_native_putFloat },
{ "putDouble", "(JD)V", (void *)JHwBlob_native_putDouble },
{ "putString", "(JLjava/lang/String;)V", (void *)JHwBlob_native_putString },
{ "putNativeHandle", "(JL" PACKAGE_PATH "/NativeHandle;)V",
(void*)JHwBlob_native_putNativeHandle },
{ "putBoolArray", "(J[Z)V", (void *)JHwBlob_native_putBoolArray },
{ "putInt8Array", "(J[B)V", (void *)JHwBlob_native_putInt8Array },

View File

@@ -27,6 +27,11 @@
namespace android {
struct JHwBlob : public RefBase {
enum class BlobType {
GENERIC,
NATIVE_HANDLE,
};
static void InitClass(JNIEnv *env);
static sp<JHwBlob> SetNativeContext(
@@ -54,6 +59,9 @@ struct JHwBlob : public RefBase {
size_t size() const;
void specializeBlobTo(BlobType type);
BlobType type() const;
status_t putBlob(size_t offset, const sp<JHwBlob> &blob);
status_t writeToParcel(hardware::Parcel *parcel) const;
@@ -74,12 +82,15 @@ private:
void *mBuffer;
size_t mSize;
BlobType mType;
bool mOwnsBuffer;
size_t mHandle;
Vector<BlobInfo> mSubBlobs;
status_t writeSubBlobsToParcel(hardware::Parcel *parcel, size_t parentHandle) const;
DISALLOW_COPY_AND_ASSIGN(JHwBlob);
};

View File

@@ -22,6 +22,7 @@
#include "android_os_HwBinder.h"
#include "android_os_HwBlob.h"
#include "android_os_NativeHandle.h"
#include "android_os_HwRemoteBinder.h"
#include <nativehelper/JNIHelp.h>
@@ -34,6 +35,7 @@
using android::AndroidRuntime;
using ::android::hardware::hidl_handle;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
@@ -436,6 +438,18 @@ static void JHwParcel_native_writeString(
signalExceptionForError(env, err);
}
static void JHwParcel_native_writeNativeHandle(JNIEnv *env, jobject thiz, jobject valObj) {
sp<JHwParcel> impl = JHwParcel::GetNativeContext(env, thiz);
EphemeralStorage *storage = impl->getStorage();
native_handle_t *handle = JNativeHandle::MakeCppNativeHandle(env, valObj, storage);
hardware::Parcel *parcel = impl->getParcel();
status_t err = parcel->writeNativeHandleNoDup(handle);
signalExceptionForError(env, err);
}
#define DEFINE_PARCEL_VECTOR_WRITER(Suffix,Type) \
static void JHwParcel_native_write ## Suffix ## Vector( \
JNIEnv *env, jobject thiz, Type ## Array valObj) { \
@@ -524,12 +538,96 @@ static void JHwParcel_native_writeBoolVector(
signalExceptionForError(env, err);
}
template<typename T>
static void WriteHidlVector(JNIEnv *env, jobject thiz, const hidl_vec<T> &vec) {
hardware::Parcel *parcel = JHwParcel::GetNativeContext(env, thiz)->getParcel();
size_t parentHandle;
status_t err = parcel->writeBuffer(&vec, sizeof(vec), &parentHandle);
if (err == OK) {
size_t childHandle;
err = ::android::hardware::writeEmbeddedToParcel(
vec,
parcel,
parentHandle,
0 /* parentOffset */,
&childHandle);
for (size_t i = 0; (err == OK) && (i < vec.size()); ++i) {
err = ::android::hardware::writeEmbeddedToParcel(
vec[i],
parcel,
childHandle,
i * sizeof(T));
}
}
signalExceptionForError(env, err);
}
static void JHwParcel_native_writeStringVector(
JNIEnv *env, jobject thiz, jobjectArray arrayObj) {
if (arrayObj == nullptr) {
jniThrowException(env, "java/lang/NullPointerException", nullptr);
return;
}
sp<JHwParcel> impl = JHwParcel::GetNativeContext(env, thiz);
EphemeralStorage *storage = impl->getStorage();
void *vecPtr = storage->allocTemporaryStorage(sizeof(hidl_vec<hidl_string>));
hidl_vec<hidl_string> *vec = new (vecPtr) hidl_vec<hidl_string>();
jsize len = env->GetArrayLength(arrayObj);
hidl_string *strings = storage->allocStringArray(len);
vec->setToExternal(strings, len, false /* shouldOwn */);
for (jsize i = 0; i < len; ++i) {
ScopedLocalRef<jstring> stringObj(env, (jstring) env->GetObjectArrayElement(arrayObj, i));
const hidl_string *s = storage->allocTemporaryString(env, stringObj.get());
strings[i].setToExternal(s->c_str(), s->size());
}
WriteHidlVector(env, thiz, *vec);
}
static void JHwParcel_native_writeNativeHandleVector(
JNIEnv *env, jobject thiz, jobjectArray jHandleArray) {
if (jHandleArray == nullptr) {
jniThrowException(env, "java/lang/NullPointerException", nullptr);
return;
}
sp<JHwParcel> impl = JHwParcel::GetNativeContext(env, thiz);
EphemeralStorage *storage = impl->getStorage();
void *vecPtr = storage->allocTemporaryStorage(sizeof(hidl_vec<hidl_handle>));
hidl_vec<hidl_handle> *vec = new (vecPtr) hidl_vec<hidl_handle>();
jsize len = env->GetArrayLength(jHandleArray);
hidl_handle *handles = static_cast<hidl_handle *>(
storage->allocTemporaryStorage(len * sizeof(hidl_handle)));
vec->setToExternal(handles, len, false /* shouldOwn */);
for (jsize i = 0; i < len; i++) {
ScopedLocalRef<jobject> jHandle(env, env->GetObjectArrayElement(jHandleArray, i));
native_handle_t* handle = JNativeHandle::MakeCppNativeHandle(env, jHandle.get(), storage);
new (&(handles[i])) hidl_handle();
handles[i].setTo(handle, false /* shouldOwn */);
}
WriteHidlVector(env, thiz, *vec);
}
static void JHwParcel_native_writeStrongBinder(
JNIEnv *env, jobject thiz, jobject binderObj) {
sp<hardware::IBinder> binder;
if (binderObj != NULL) {
ScopedLocalRef<jclass> hwBinderKlass(
env, FindClassOrDie(env, PACKAGE_PATH "/HwBinder"));
ScopedLocalRef<jclass> hwBinderKlass(env, FindClassOrDie(env, PACKAGE_PATH "/HwBinder"));
ScopedLocalRef<jclass> hwRemoteBinderKlass(
env, FindClassOrDie(env, PACKAGE_PATH "/HwRemoteBinder"));
@@ -587,6 +685,37 @@ static jstring JHwParcel_native_readString(JNIEnv *env, jobject thiz) {
return MakeStringObjFromHidlString(env, *s);
}
static jobject ReadNativeHandle(JNIEnv *env, jobject thiz, jboolean embedded,
jlong parentHandle, jlong offset) {
hardware::Parcel *parcel =
JHwParcel::GetNativeContext(env, thiz)->getParcel();
const native_handle_t *handle = nullptr;
status_t err = OK;
if (embedded) {
err = parcel->readNullableEmbeddedNativeHandle(parentHandle, offset, &handle);
} else {
err = parcel->readNullableNativeHandleNoDup(&handle);
}
if (err != OK) {
signalExceptionForError(env, err);
return nullptr;
}
return JNativeHandle::MakeJavaNativeHandleObj(env, handle);
}
static jobject JHwParcel_native_readNativeHandle(JNIEnv *env, jobject thiz) {
return ReadNativeHandle(env, thiz, false /*embedded*/, 0L /*parentHandle*/, 0L /*offset*/);
}
static jobject JHwParcel_native_readEmbeddedNativeHandle(
JNIEnv *env, jobject thiz, jlong parentHandle, jlong offset) {
return ReadNativeHandle(env, thiz, true /*embedded*/, parentHandle, offset);
}
#define DEFINE_PARCEL_VECTOR_READER(Suffix,Type,NewType) \
static Type ## Array JHwParcel_native_read ## Suffix ## Vector( \
JNIEnv *env, jobject thiz) { \
@@ -630,10 +759,8 @@ DEFINE_PARCEL_VECTOR_READER(Int64,jlong,Long)
DEFINE_PARCEL_VECTOR_READER(Float,jfloat,Float)
DEFINE_PARCEL_VECTOR_READER(Double,jdouble,Double)
static jbooleanArray JHwParcel_native_readBoolVector(
JNIEnv *env, jobject thiz) {
hardware::Parcel *parcel =
JHwParcel::GetNativeContext(env, thiz)->getParcel();
static jbooleanArray JHwParcel_native_readBoolVector(JNIEnv *env, jobject thiz) {
hardware::Parcel *parcel = JHwParcel::GetNativeContext(env, thiz)->getParcel();
size_t parentHandle;
@@ -692,101 +819,62 @@ static jobjectArray MakeStringArray(
return arrayObj;
}
static jobjectArray JHwParcel_native_readStringVector(
JNIEnv *env, jobject thiz) {
typedef hidl_vec<hidl_string> string_vec;
template<typename T>
static const hidl_vec<T> *ReadHidlVector(JNIEnv *env, jobject thiz) {
const hidl_vec<T> *vec;
hardware::Parcel *parcel =
JHwParcel::GetNativeContext(env, thiz)->getParcel();
hardware::Parcel *parcel = JHwParcel::GetNativeContext(env, thiz)->getParcel();
size_t parentHandle;
const string_vec *vec;
status_t err = parcel->readBuffer(sizeof(*vec), &parentHandle,
reinterpret_cast<const void **>(&vec));
if (err != OK) {
signalExceptionForError(env, err);
return NULL;
}
size_t childHandle;
err = ::android::hardware::readEmbeddedFromParcel(
const_cast<string_vec &>(*vec),
*parcel, parentHandle, 0 /* parentOffset */, &childHandle);
for (size_t i = 0; (err == OK) && (i < vec->size()); ++i) {
err = android::hardware::readEmbeddedFromParcel(
const_cast<hidl_string &>((*vec)[i]),
*parcel,
childHandle,
i * sizeof(hidl_string) /* parentOffset */);
}
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<hidl_string> string_vec;
if (arrayObj == NULL) {
jniThrowException(env, "java/lang/NullPointerException", NULL);
return;
}
jsize len = env->GetArrayLength(arrayObj);
sp<JHwParcel> impl = JHwParcel::GetNativeContext(env, thiz);
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);
for (jsize i = 0; i < len; ++i) {
ScopedLocalRef<jstring> 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);
status_t err = parcel->readBuffer(sizeof(hidl_vec<T>),
&parentHandle, reinterpret_cast<const void **>(&vec));
if (err == OK) {
size_t childHandle;
err = ::android::hardware::writeEmbeddedToParcel(
*vec,
parcel,
parentHandle,
err = ::android::hardware::readEmbeddedFromParcel(
const_cast<hidl_vec<T> &>(*vec),
*parcel, parentHandle,
0 /* parentOffset */,
&childHandle);
for (size_t i = 0; (err == OK) && (i < vec->size()); ++i) {
err = ::android::hardware::writeEmbeddedToParcel(
(*vec)[i],
parcel,
for (size_t i = 0; (err == OK) && (i < vec->size()); i++) {
err = android::hardware::readEmbeddedFromParcel(
const_cast<T &>((*vec)[i]),
*parcel,
childHandle,
i * sizeof(hidl_string));
i * sizeof(T) /* parentOffset */);
}
}
signalExceptionForError(env, err);
if (err != OK) {
signalExceptionForError(env, err);
return nullptr;
}
return vec;
}
static jobjectArray JHwParcel_native_readStringVector(
JNIEnv *env, jobject thiz) {
const hidl_vec<hidl_string> *vec = ReadHidlVector<hidl_string>(env, thiz);
return MakeStringArray(env, &(*vec)[0], vec->size());
}
static jobjectArray JHwParcel_native_readNativeHandleVector(
JNIEnv *env, jobject thiz) {
const hidl_vec<hidl_handle> *vec = ReadHidlVector<hidl_handle>(env, thiz);
jsize length = vec->size();
jobjectArray objArray = JNativeHandle::AllocJavaNativeHandleObjArray(
env, length);
for (jsize i = 0; i < length; i++) {
jobject jHandle = JNativeHandle::MakeJavaNativeHandleObj(env, (*vec)[i].getNativeHandle());
env->SetObjectArrayElement(objArray, i, jHandle);
}
return objArray;
}
static jobject JHwParcel_native_readStrongBinder(JNIEnv *env, jobject thiz) {
@@ -890,6 +978,9 @@ static JNINativeMethod gMethods[] = {
{ "writeString", "(Ljava/lang/String;)V",
(void *)JHwParcel_native_writeString },
{ "writeNativeHandle", "(L" PACKAGE_PATH "/NativeHandle;)V",
(void *)JHwParcel_native_writeNativeHandle },
{ "writeBoolVector", "([Z)V", (void *)JHwParcel_native_writeBoolVector },
{ "writeInt8Vector", "([B)V", (void *)JHwParcel_native_writeInt8Vector },
{ "writeInt16Vector", "([S)V", (void *)JHwParcel_native_writeInt16Vector },
@@ -903,6 +994,9 @@ static JNINativeMethod gMethods[] = {
{ "writeStringVector", "([Ljava/lang/String;)V",
(void *)JHwParcel_native_writeStringVector },
{ "writeNativeHandleVector", "([L" PACKAGE_PATH "/NativeHandle;)V",
(void *)JHwParcel_native_writeNativeHandleVector },
{ "writeStrongBinder", "(L" PACKAGE_PATH "/IHwBinder;)V",
(void *)JHwParcel_native_writeStrongBinder },
@@ -920,6 +1014,12 @@ static JNINativeMethod gMethods[] = {
{ "readString", "()Ljava/lang/String;",
(void *)JHwParcel_native_readString },
{ "readNativeHandle", "()L" PACKAGE_PATH "/NativeHandle;",
(void *)JHwParcel_native_readNativeHandle },
{ "readEmbeddedNativeHandle", "(JJ)L" PACKAGE_PATH "/NativeHandle;",
(void *)JHwParcel_native_readEmbeddedNativeHandle },
{ "readBoolVectorAsArray", "()[Z",
(void *)JHwParcel_native_readBoolVector },
@@ -944,6 +1044,9 @@ static JNINativeMethod gMethods[] = {
{ "readStringVectorAsArray", "()[Ljava/lang/String;",
(void *)JHwParcel_native_readStringVector },
{ "readNativeHandleAsArray", "()[L" PACKAGE_PATH "/NativeHandle;",
(void *)JHwParcel_native_readNativeHandleVector },
{ "readStrongBinder", "()L" PACKAGE_PATH "/IHwBinder;",
(void *)JHwParcel_native_readStrongBinder },

View File

@@ -0,0 +1,103 @@
/*
* Copyright (C) 2018 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.
*/
#include "android_os_NativeHandle.h"
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedLocalRef.h>
#include "core_jni_helpers.h"
#define PACKAGE_PATH "android/os"
#define CLASS_NAME "NativeHandle"
#define CLASS_PATH PACKAGE_PATH "/" CLASS_NAME
namespace android {
static struct {
jclass clazz;
jmethodID constructID; // NativeHandle(int[] fds, int[] ints, boolean owns)
jmethodID getFdsID; // int[] NativeHandle.getFds()
jmethodID getIntsID; // int[] NativeHandle.getInts()
} gNativeHandleFields;
jobject JNativeHandle::MakeJavaNativeHandleObj(
JNIEnv *env, const native_handle_t *handle) {
if (handle == nullptr) { return nullptr; }
const int numFds = handle->numFds;
ScopedLocalRef<jintArray> fds(env, env->NewIntArray(numFds));
env->SetIntArrayRegion(fds.get(), 0, numFds, &(handle->data[0]));
const int numInts = handle->numInts;
ScopedLocalRef<jintArray> ints(env, env->NewIntArray(numInts));
env->SetIntArrayRegion(ints.get(), 0, numInts, &(handle->data[numFds]));
return env->NewObject(gNativeHandleFields.clazz,
gNativeHandleFields.constructID, fds.get(), ints.get(), false /*own*/);
}
native_handle_t *JNativeHandle::MakeCppNativeHandle(
JNIEnv *env, jobject jHandle, EphemeralStorage *storage) {
if (jHandle == nullptr) { return nullptr; }
if (!env->IsInstanceOf(jHandle, gNativeHandleFields.clazz)) {
jniThrowException(env, "java/lang/ClassCastException",
"jHandle must be an instance of NativeHandle.");
return nullptr;
}
ScopedLocalRef<jintArray> fds(env, (jintArray) env->CallObjectMethod(
jHandle, gNativeHandleFields.getFdsID));
ScopedLocalRef<jintArray> ints(env, (jintArray) env->CallObjectMethod(
jHandle, gNativeHandleFields.getIntsID));
const int numFds = (int) env->GetArrayLength(fds.get());
const int numInts = (int) env->GetArrayLength(ints.get());
native_handle_t *handle = (storage == nullptr)
? native_handle_create(numFds, numInts)
: storage->allocTemporaryNativeHandle(numFds, numInts);
if (handle != nullptr) {
env->GetIntArrayRegion(fds.get(), 0, numFds, &(handle->data[0]));
env->GetIntArrayRegion(ints.get(), 0, numInts, &(handle->data[numFds]));
} else {
jniThrowException(env, "java/lang/OutOfMemoryError",
"Failed to allocate memory for native_handle_t.");
}
return handle;
}
jobjectArray JNativeHandle::AllocJavaNativeHandleObjArray(JNIEnv *env, jsize length) {
return env->NewObjectArray(length, gNativeHandleFields.clazz, nullptr);
}
int register_android_os_NativeHandle(JNIEnv *env) {
jclass clazz = FindClassOrDie(env, CLASS_PATH);
gNativeHandleFields.clazz = MakeGlobalRefOrDie(env, clazz);
gNativeHandleFields.constructID = GetMethodIDOrDie(env, clazz, "<init>", "([I[IZ)V");
gNativeHandleFields.getFdsID = GetMethodIDOrDie(env, clazz, "getFdsAsIntArray", "()[I");
gNativeHandleFields.getIntsID = GetMethodIDOrDie(env, clazz, "getInts", "()[I");
return 0;
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2018 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_NATIVE_HANDLE_H
#define ANDROID_OS_NATIVE_HANDLE_H
#include "hwbinder/EphemeralStorage.h"
#include <cutils/native_handle.h>
#include <jni.h>
namespace android {
struct JNativeHandle {
/**
* Returns a Java NativeHandle object representing the parameterized
* native_handle_t instance.
*/
static jobject MakeJavaNativeHandleObj(JNIEnv *env, const native_handle_t *handle);
/**
* Returns a heap-allocated native_handle_t instance representing the
* parameterized Java object. Note that if no valid EphemeralStorage*
* parameter is supplied (storage is nullptr), the return value must
* be explicitly deallocated (using native_handle_delete).
*/
static native_handle_t* MakeCppNativeHandle(JNIEnv *env, jobject jHandle,
EphemeralStorage *storage);
/**
* Returns an (uninitialized) array of Java NativeHandle objects.
*/
static jobjectArray AllocJavaNativeHandleObjArray(JNIEnv *env, jsize length);
};
}
#endif // ANDROID_OS_NATIVE_HANDLE_H

View File

@@ -71,6 +71,17 @@ const hidl_string *EphemeralStorage::allocTemporaryString(
return s;
}
native_handle_t *EphemeralStorage::allocTemporaryNativeHandle(
int numFds, int numInts) {
Item item;
item.mType = TYPE_NATIVE_HANDLE;
item.mObj = nullptr;
item.mPtr = native_handle_create(numFds, numInts);
mItems.push_back(item);
return static_cast<native_handle_t*>(item.mPtr);
}
#define DEFINE_ALLOC_VECTOR_METHODS(Suffix,Type,NewType) \
const hidl_vec<Type> *EphemeralStorage::allocTemporary ## Suffix ## Vector( \
JNIEnv *env, Type ## Array arrayObj) { \
@@ -145,6 +156,13 @@ void EphemeralStorage::release(JNIEnv *env) {
DEFINE_RELEASE_ARRAY_CASE(Float,jfloat,Float)
DEFINE_RELEASE_ARRAY_CASE(Double,jdouble,Double)
case TYPE_NATIVE_HANDLE:
{
int err = native_handle_delete(static_cast<native_handle_t *>(item.mPtr));
CHECK(err == 0);
break;
}
default:
CHECK(!"Should not be here");
}

View File

@@ -43,6 +43,8 @@ struct EphemeralStorage {
const ::android::hardware::hidl_string *allocTemporaryString(
JNIEnv *env, jstring stringObj);
native_handle_t *allocTemporaryNativeHandle(int numFds, int numInts);
DECLARE_ALLOC_METHODS(Int8,jbyte)
DECLARE_ALLOC_METHODS(Int16,jshort)
DECLARE_ALLOC_METHODS(Int32,jint)
@@ -61,6 +63,7 @@ private:
TYPE_Int64_ARRAY,
TYPE_Float_ARRAY,
TYPE_Double_ARRAY,
TYPE_NATIVE_HANDLE,
};
struct Item {