Merge changes from topic "hidl-memory-java"
am: 887aa66d0a
Change-Id: If36ca2aad9c3e68e5a5be49e9e1566e44f40511b
diff --git a/Android.bp b/Android.bp
index b8d8bc8..c7549ba 100644
--- a/Android.bp
+++ b/Android.bp
@@ -816,11 +816,13 @@
srcs: [
"core/java/android/os/HidlSupport.java",
"core/java/android/annotation/IntDef.java",
+ "core/java/android/annotation/IntRange.java",
"core/java/android/annotation/NonNull.java",
"core/java/android/annotation/Nullable.java",
"core/java/android/annotation/SystemApi.java",
"core/java/android/annotation/TestApi.java",
"core/java/android/annotation/UnsupportedAppUsage.java",
+ "core/java/android/os/HidlMemory.java",
"core/java/android/os/HwBinder.java",
"core/java/android/os/HwBlob.java",
"core/java/android/os/HwParcel.java",
@@ -1358,8 +1360,10 @@
srcs: [
"core/java/android/os/HidlSupport.java",
"core/java/android/annotation/IntDef.java",
+ "core/java/android/annotation/IntRange.java",
"core/java/android/annotation/NonNull.java",
"core/java/android/annotation/SystemApi.java",
+ "core/java/android/os/HidlMemory.java",
"core/java/android/os/HwBinder.java",
"core/java/android/os/HwBlob.java",
"core/java/android/os/HwParcel.java",
diff --git a/api/system-current.txt b/api/system-current.txt
index 7a625e1..b46090a 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5246,6 +5246,17 @@
method @NonNull public static java.io.File getVendorDirectory();
}
+ public class HidlMemory implements java.io.Closeable {
+ ctor public HidlMemory(@NonNull String, @IntRange(from=0) long, @Nullable android.os.NativeHandle);
+ method public void close() throws java.io.IOException;
+ method @NonNull public android.os.HidlMemory dup() throws java.io.IOException;
+ method protected void finalize();
+ method @Nullable public android.os.NativeHandle getHandle();
+ method @NonNull public String getName();
+ method public long getSize();
+ method @NonNull public android.os.NativeHandle releaseHandle();
+ }
+
public class HidlSupport {
method public static boolean deepEquals(Object, Object);
method public static int deepHashCode(Object);
@@ -5276,6 +5287,7 @@
method public final void copyToInt8Array(long, byte[], int);
method public final boolean getBool(long);
method public final double getDouble(long);
+ method public final long getFieldHandle(long);
method public final float getFloat(long);
method public final short getInt16(long);
method public final int getInt32(long);
@@ -5290,6 +5302,7 @@
method public final void putDoubleArray(long, double[]);
method public final void putFloat(long, float);
method public final void putFloatArray(long, float[]);
+ method public final void putHidlMemory(long, @NonNull android.os.HidlMemory);
method public final void putInt16(long, short);
method public final void putInt16Array(long, short[]);
method public final void putInt32(long, int);
@@ -5318,9 +5331,11 @@
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 @NonNull @Nullable public final android.os.HidlMemory readEmbeddedHidlMemory(long, long, long);
method @Nullable public final android.os.NativeHandle readEmbeddedNativeHandle(long, long);
method public final float readFloat();
method public final java.util.ArrayList<java.lang.Float> readFloatVector();
+ method @NonNull public final android.os.HidlMemory readHidlMemory();
method public final short readInt16();
method public final java.util.ArrayList<java.lang.Short> readInt16Vector();
method public final int readInt32();
@@ -5345,6 +5360,7 @@
method public final void writeDoubleVector(java.util.ArrayList<java.lang.Double>);
method public final void writeFloat(float);
method public final void writeFloatVector(java.util.ArrayList<java.lang.Float>);
+ method public final void writeHidlMemory(@NonNull android.os.HidlMemory);
method public final void writeInt16(short);
method public final void writeInt16Vector(java.util.ArrayList<java.lang.Short>);
method public final void writeInt32(int);
diff --git a/api/test-current.txt b/api/test-current.txt
index 2a47500..1ed4c4c 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1724,6 +1724,17 @@
method public static boolean contains(java.io.File, java.io.File);
}
+ public class HidlMemory implements java.io.Closeable {
+ ctor public HidlMemory(@NonNull String, @IntRange(from=0) long, @Nullable android.os.NativeHandle);
+ method public void close() throws java.io.IOException;
+ method @NonNull public android.os.HidlMemory dup() throws java.io.IOException;
+ method protected void finalize();
+ method @Nullable public android.os.NativeHandle getHandle();
+ method @NonNull public String getName();
+ method public long getSize();
+ method @NonNull public android.os.NativeHandle releaseHandle();
+ }
+
public abstract class HwBinder implements android.os.IHwBinder {
ctor public HwBinder();
method public static final void configureRpcThreadpool(long, boolean);
@@ -1747,6 +1758,7 @@
method public final void copyToInt8Array(long, byte[], int);
method public final boolean getBool(long);
method public final double getDouble(long);
+ method public final long getFieldHandle(long);
method public final float getFloat(long);
method public final short getInt16(long);
method public final int getInt32(long);
@@ -1761,6 +1773,7 @@
method public final void putDoubleArray(long, double[]);
method public final void putFloat(long, float);
method public final void putFloatArray(long, float[]);
+ method public final void putHidlMemory(long, @NonNull android.os.HidlMemory);
method public final void putInt16(long, short);
method public final void putInt16Array(long, short[]);
method public final void putInt32(long, int);
@@ -1789,9 +1802,11 @@
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 @NonNull @Nullable public final android.os.HidlMemory readEmbeddedHidlMemory(long, long, long);
method @Nullable public final android.os.NativeHandle readEmbeddedNativeHandle(long, long);
method public final float readFloat();
method public final java.util.ArrayList<java.lang.Float> readFloatVector();
+ method @NonNull public final android.os.HidlMemory readHidlMemory();
method public final short readInt16();
method public final java.util.ArrayList<java.lang.Short> readInt16Vector();
method public final int readInt32();
@@ -1816,6 +1831,7 @@
method public final void writeDoubleVector(java.util.ArrayList<java.lang.Double>);
method public final void writeFloat(float);
method public final void writeFloatVector(java.util.ArrayList<java.lang.Float>);
+ method public final void writeHidlMemory(@NonNull android.os.HidlMemory);
method public final void writeInt16(short);
method public final void writeInt16Vector(java.util.ArrayList<java.lang.Short>);
method public final void writeInt32(int);
diff --git a/core/java/android/os/HidlMemory.java b/core/java/android/os/HidlMemory.java
new file mode 100644
index 0000000..aeb6589
--- /dev/null
+++ b/core/java/android/os/HidlMemory.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2019 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.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+/**
+ * An abstract representation of a memory block, as representing by the HIDL system.
+ *
+ * The block is defined by a {name, size, handle} tuple, where the name is used to determine how to
+ * interpret the handle. The underlying handle is assumed to be owned by this instance and will be
+ * closed as soon as {@link #close()} is called on this instance, or this instance has been
+ * finalized (the latter supports using it in a shared manner without having to worry about who owns
+ * this instance, the former is more efficient resource-wise and is recommended for most use-cases).
+ * Note, however, that ownership of the handle does not necessarily imply ownership of the
+ * underlying file descriptors - the underlying handle may or may not own them. If you want the
+ * underlying handle to outlive this instance, call {@link #releaseHandle()} to obtain the handle
+ * and detach the ownership relationship.
+ *
+ * @hide
+ */
+@SystemApi
+@TestApi
+public class HidlMemory implements Closeable {
+ private final @NonNull String mName;
+ private final long mSize;
+ private @Nullable NativeHandle mHandle;
+ private long mNativeContext; // For use of native code.
+
+ /**
+ * Constructor.
+ *
+ * @param name The name of the IMapper service used to resolve the handle (e.g. "ashmem").
+ * @param size The (non-negative) size in bytes of the memory block.
+ * @param handle The handle. May be null. This instance will own the handle and will close it
+ * as soon as {@link #close()} is called or the object is destroyed. This, this
+ * handle instance should generally not be shared with other clients.
+ */
+ public HidlMemory(@NonNull String name, @IntRange(from = 0) long size,
+ @Nullable NativeHandle handle) {
+ mName = name;
+ mSize = size;
+ mHandle = handle;
+ }
+
+ /**
+ * Create a copy of this instance, where the underlying handle (and its file descriptors) have
+ * been duplicated.
+ */
+ @NonNull
+ public HidlMemory dup() throws IOException {
+ return new HidlMemory(mName, mSize, mHandle != null ? mHandle.dup() : null);
+ }
+
+ /**
+ * Close the underlying native handle. No-op if handle is null or has been released using {@link
+ * #releaseHandle()}.
+ */
+ @Override
+ public void close() throws IOException {
+ if (mHandle != null) {
+ mHandle.close();
+ }
+ }
+
+ /**
+ * Disowns the underlying handle and returns it. This object becomes invalid.
+ *
+ * @return The underlying handle.
+ */
+ @NonNull
+ public NativeHandle releaseHandle() {
+ NativeHandle handle = mHandle;
+ mHandle = null;
+ return handle;
+ }
+
+ /**
+ * Gets the name, which represents how the handle is to be interpreted.
+ *
+ * @return The name.
+ */
+ @NonNull
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * Gets the size of the block, in bytes.
+ *
+ * @return The size.
+ */
+ public long getSize() {
+ return mSize;
+ }
+
+ /**
+ * Gets a native handle. The actual interpretation depends on the name and is implementation
+ * defined.
+ *
+ * @return The native handle.
+ */
+ @Nullable
+ public NativeHandle getHandle() {
+ return mHandle;
+ }
+
+ @Override
+ protected void finalize() {
+ try {
+ close();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ } finally {
+ nativeFinalize();
+ }
+ }
+
+ private native void nativeFinalize();
+}
diff --git a/core/java/android/os/HidlMemoryUtil.java b/core/java/android/os/HidlMemoryUtil.java
new file mode 100644
index 0000000..b08822d
--- /dev/null
+++ b/core/java/android/os/HidlMemoryUtil.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2019 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 static android.system.OsConstants.MAP_SHARED;
+import static android.system.OsConstants.PROT_READ;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.util.Log;
+
+import com.android.internal.util.Preconditions;
+
+import java.nio.ByteBuffer;
+import java.nio.DirectByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Provides utilities for dealing with HidlMemory.
+ *
+ * @hide
+ */
+public final class HidlMemoryUtil {
+ static private final String TAG = "HidlMemoryUtil";
+
+ private HidlMemoryUtil() {
+ }
+
+ /**
+ * Copies a byte-array into a new Ashmem region and return it as HidlMemory.
+ * The returned instance owns the underlying file descriptors, and the client should generally
+ * call close on it when no longer in use (or otherwise, when the object gets destroyed it will
+ * be closed).
+ *
+ * @param input The input byte array.
+ * @return A HidlMemory instance, containing a copy of the input.
+ */
+ public static @NonNull
+ HidlMemory byteArrayToHidlMemory(@NonNull byte[] input) {
+ return byteArrayToHidlMemory(input, null);
+ }
+
+ /**
+ * Copies a byte-array into a new Ashmem region and return it as HidlMemory.
+ * The returned instance owns the underlying file descriptors, and the client should generally
+ * call close on it when no longer in use (or otherwise, when the object gets destroyed it will
+ * be closed).
+ *
+ * @param input The input byte array.
+ * @param name An optional name for the ashmem region.
+ * @return A HidlMemory instance, containing a copy of the input.
+ */
+ public static @NonNull
+ HidlMemory byteArrayToHidlMemory(@NonNull byte[] input, @Nullable String name) {
+ Preconditions.checkNotNull(input);
+
+ if (input.length == 0) {
+ return new HidlMemory("ashmem", 0, null);
+ }
+
+ try {
+ SharedMemory shmem = SharedMemory.create(name != null ? name : "", input.length);
+ ByteBuffer buffer = shmem.mapReadWrite();
+ buffer.put(input);
+ shmem.unmap(buffer);
+ NativeHandle handle = new NativeHandle(shmem.getFileDescriptor(), true);
+ return new HidlMemory("ashmem", input.length, handle);
+ } catch (ErrnoException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Copies a byte list into a new Ashmem region and return it as HidlMemory.
+ * The returned instance owns the underlying file descriptors, and the client should generally
+ * call close on it when no longer in use (or otherwise, when the object gets destroyed it will
+ * be closed).
+ *
+ * @param input The input byte list.
+ * @return A HidlMemory instance, containing a copy of the input.
+ */
+ public static @NonNull
+ HidlMemory byteListToHidlMemory(@NonNull List<Byte> input) {
+ return byteListToHidlMemory(input, null);
+ }
+
+ /**
+ * Copies a byte list into a new Ashmem region and return it as HidlMemory.
+ * The returned instance owns the underlying file descriptors, and the client should generally
+ * call close on it when no longer in use (or otherwise, when the object gets destroyed it will
+ * be closed).
+ *
+ * @param input The input byte list.
+ * @param name An optional name for the ashmem region.
+ * @return A HidlMemory instance, containing a copy of the input.
+ */
+ public static @NonNull
+ HidlMemory byteListToHidlMemory(@NonNull List<Byte> input, @Nullable String name) {
+ Preconditions.checkNotNull(input);
+
+ if (input.isEmpty()) {
+ return new HidlMemory("ashmem", 0, null);
+ }
+
+ try {
+ SharedMemory shmem = SharedMemory.create(name != null ? name : "", input.size());
+ ByteBuffer buffer = shmem.mapReadWrite();
+ for (Byte b : input) {
+ buffer.put(b);
+ }
+ shmem.unmap(buffer);
+ NativeHandle handle = new NativeHandle(shmem.getFileDescriptor(), true);
+ return new HidlMemory("ashmem", input.size(), handle);
+ } catch (ErrnoException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Copies all data from a HidlMemory instance into a byte array.
+ *
+ * @param mem The HidlMemory instance. Must be of name "ashmem" and of size that doesn't exceed
+ * {@link Integer#MAX_VALUE}.
+ * @return A byte array, containing a copy of the input.
+ */
+ public static @NonNull
+ byte[] hidlMemoryToByteArray(@NonNull HidlMemory mem) {
+ Preconditions.checkNotNull(mem);
+ Preconditions.checkArgumentInRange(mem.getSize(), 0L, (long) Integer.MAX_VALUE,
+ "Memory size");
+ Preconditions.checkArgument(mem.getSize() == 0 || mem.getName().equals("ashmem"),
+ "Unsupported memory type: %s", mem.getName());
+
+ if (mem.getSize() == 0) {
+ return new byte[0];
+ }
+
+ ByteBuffer buffer = getBuffer(mem);
+ byte[] result = new byte[buffer.remaining()];
+ buffer.get(result);
+ return result;
+ }
+
+ /**
+ * Copies all data from a HidlMemory instance into a byte list.
+ *
+ * @param mem The HidlMemory instance. Must be of name "ashmem" and of size that doesn't exceed
+ * {@link Integer#MAX_VALUE}.
+ * @return A byte list, containing a copy of the input.
+ */
+ @SuppressLint("ConcreteCollection")
+ public static @NonNull
+ ArrayList<Byte> hidlMemoryToByteList(@NonNull HidlMemory mem) {
+ Preconditions.checkNotNull(mem);
+ Preconditions.checkArgumentInRange(mem.getSize(), 0L, (long) Integer.MAX_VALUE,
+ "Memory size");
+ Preconditions.checkArgument(mem.getSize() == 0 || mem.getName().equals("ashmem"),
+ "Unsupported memory type: %s", mem.getName());
+
+ if (mem.getSize() == 0) {
+ return new ArrayList<>();
+ }
+
+ ByteBuffer buffer = getBuffer(mem);
+
+ ArrayList<Byte> result = new ArrayList<>(buffer.remaining());
+ while (buffer.hasRemaining()) {
+ result.add(buffer.get());
+ }
+ return result;
+ }
+
+ private static ByteBuffer getBuffer(@NonNull HidlMemory mem) {
+ try {
+ final int size = (int) mem.getSize();
+
+ if (size == 0) {
+ return ByteBuffer.wrap(new byte[0]);
+ }
+
+ NativeHandle handle = mem.getHandle();
+
+ final long address = Os.mmap(0, size, PROT_READ, MAP_SHARED, handle.getFileDescriptor(),
+ 0);
+ return new DirectByteBuffer(size, address, handle.getFileDescriptor(), () -> {
+ try {
+ Os.munmap(address, size);
+ } catch (ErrnoException e) {
+ Log.wtf(TAG, e);
+ }
+ }, true);
+ } catch (ErrnoException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/core/java/android/os/HwBlob.java b/core/java/android/os/HwBlob.java
index 2c453bf..154227b2 100644
--- a/core/java/android/os/HwBlob.java
+++ b/core/java/android/os/HwBlob.java
@@ -92,6 +92,14 @@
* @throws IndexOutOfBoundsException when offset is out of this HwBlob
*/
public native final String getString(long offset);
+ /**
+ * For embedded fields that follow a two-step approach for reading, first obtain their field
+ * handle using this method, and pass that field handle to the respective
+ * HwParcel.readEmbedded*() method.
+ * @param offset The field offset.
+ * @return The field handle.
+ */
+ public native final long getFieldHandle(long offset);
/**
* Copy the blobs data starting from the given byte offset into the range, copying
@@ -312,6 +320,20 @@
public native final void putBlob(long offset, HwBlob blob);
/**
+ * Writes a HidlMemory instance (without duplicating the underlying file descriptors) at an
+ * offset.
+ *
+ * @param offset location to write value
+ * @param mem a {@link HidlMemory} instance to write
+ * @throws IndexOutOfBoundsException when [offset, offset + sizeof(jobject)] is out of range
+ */
+ public final void putHidlMemory(long offset, @NonNull HidlMemory mem) {
+ putNativeHandle(offset + 0 /* offset of 'handle' field. */, mem.getHandle());
+ putInt64(offset + 16 /* offset of 'size' field. */, mem.getSize());
+ putString(offset + 24 /* offset of 'name' field. */, mem.getName());
+ }
+
+ /**
* @return current handle of HwBlob for reference in a parcelled binder transaction
*/
public native final long handle();
diff --git a/core/java/android/os/HwParcel.java b/core/java/android/os/HwParcel.java
index 5e8929c..9786f16 100644
--- a/core/java/android/os/HwParcel.java
+++ b/core/java/android/os/HwParcel.java
@@ -324,6 +324,15 @@
public native final void writeStrongBinder(IHwBinder binder);
/**
+ * Write a HidlMemory object (without duplicating the underlying file descriptors) to the end
+ * of the parcel.
+ *
+ * @param memory value to write
+ */
+ @FastNative
+ public native final void writeHidlMemory(@NonNull HidlMemory memory);
+
+ /**
* Checks to make sure that the interface name matches the name written by the parcel
* sender by writeInterfaceToken
*
@@ -582,6 +591,38 @@
public native final IHwBinder readStrongBinder();
/**
+ * Reads a HidlMemory value (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 HidlMemory#dup()}, which makes you also
+ * responsible for calling {@link HidlMemory#close()}.
+ *
+ * @return HidlMemory object read from parcel.
+ * @throws IllegalArgumentException if the parcel has no more data or is otherwise corrupt.
+ */
+ @FastNative
+ @NonNull
+ public native final HidlMemory readHidlMemory();
+
+ /**
+ * Reads an embedded HidlMemory (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 HidlMemory#dup()}. You
+ * do not need to call close on the HidlMemory returned from this.
+ *
+ * @param fieldHandle handle of the field, obtained from the {@link HwBlob}.
+ * @param parentHandle parentHandle from which to read the embedded object
+ * @param offset offset into parent
+ * @return a {@link HidlMemory} instance parsed from the parcel
+ * @throws IllegalArgumentException if the parcel has no more data
+ */
+ @FastNative
+ @NonNull
+ public native final @Nullable
+ HidlMemory readEmbeddedHidlMemory(long fieldHandle, long parentHandle, long offset);
+
+ /**
* Read opaque segment of data as a blob.
* @return blob of size expectedSize
* @throws IllegalArgumentException if the parcel has no more data
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 486d24c..7b61277 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -87,6 +87,7 @@
"android_text_Hyphenator.cpp",
"android_os_Debug.cpp",
"android_os_GraphicsEnvironment.cpp",
+ "android_os_HidlMemory.cpp",
"android_os_HidlSupport.cpp",
"android_os_HwBinder.cpp",
"android_os_HwBlob.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 9e4c222..2383731 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -191,6 +191,7 @@
extern int register_android_os_Trace(JNIEnv* env);
extern int register_android_os_FileObserver(JNIEnv *env);
extern int register_android_os_UEventObserver(JNIEnv* env);
+extern int register_android_os_HidlMemory(JNIEnv* env);
extern int register_android_os_MemoryFile(JNIEnv* env);
extern int register_android_os_SharedMemory(JNIEnv* env);
extern int register_android_net_LocalSocketImpl(JNIEnv* env);
@@ -1474,6 +1475,7 @@
REG_JNI(register_android_os_SystemProperties),
REG_JNI(register_android_os_Binder),
REG_JNI(register_android_os_Parcel),
+ REG_JNI(register_android_os_HidlMemory),
REG_JNI(register_android_os_HidlSupport),
REG_JNI(register_android_os_HwBinder),
REG_JNI(register_android_os_HwBlob),
diff --git a/core/jni/android_os_HidlMemory.cpp b/core/jni/android_os_HidlMemory.cpp
new file mode 100644
index 0000000..69e4818
--- /dev/null
+++ b/core/jni/android_os_HidlMemory.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2019 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_HidlMemory.h"
+#include "core_jni_helpers.h"
+#include "android_os_NativeHandle.h"
+
+#define PACKAGE_PATH "android/os"
+#define CLASS_NAME "HidlMemory"
+#define CLASS_PATH PACKAGE_PATH "/" CLASS_NAME
+
+namespace android {
+
+namespace {
+
+static struct {
+ jclass clazz;
+ jfieldID nativeContext; // long
+ jmethodID constructor; // HidlMemory(String, long, NativeHandle)
+ jmethodID getName; // String HidlMemory.getName()
+ jmethodID getSize; // int HidlMemory.getSize()
+ jmethodID getHandle; // NativeHandle HidlMemory.getHandle()
+} gFields;
+
+std::string stringFromJava(JNIEnv* env, jstring jstr) {
+ ScopedUtfChars s(env, jstr);
+ return s.c_str();
+}
+
+jstring stringToJava(JNIEnv* env, const std::string& cstr) {
+ return env->NewStringUTF(cstr.c_str());
+}
+
+static void nativeFinalize(JNIEnv* env, jobject jobj) {
+ jlong jNativeContext = env->GetLongField(jobj, gFields.nativeContext);
+ JHidlMemory* native = reinterpret_cast<JHidlMemory*>(jNativeContext);
+ delete native;
+}
+
+static JNINativeMethod gMethods[] = {
+ {"nativeFinalize", "()V", (void*) nativeFinalize},
+};
+
+} // namespace
+
+JHidlMemory::~JHidlMemory() {
+ if (mObj) {
+ // Must manually delete the underlying handle - hidl_memory doesn't own
+ // it.
+ native_handle_delete(const_cast<native_handle_t*>(mObj->handle()));
+ }
+}
+
+/* static */ const hardware::hidl_memory* JHidlMemory::fromJava(JNIEnv* env,
+ jobject jobj) {
+ // Try to get the result from cache.
+ env->MonitorEnter(jobj);
+ JHidlMemory* obj = getNativeContext(env, jobj);
+ if (!obj->mObj) {
+ // Create and cache.
+ obj->mObj = javaToNative(env, jobj);
+ }
+ env->MonitorExit(jobj);
+ return obj->mObj.get();
+}
+
+/* static */ jobject JHidlMemory::toJava(JNIEnv* env,
+ const hardware::hidl_memory& cobj) {
+ if (cobj.size() > std::numeric_limits<jlong>::max()) {
+ return nullptr;
+ }
+ jstring jname = stringToJava(env, cobj.name());
+ jlong jsize = static_cast<jlong>(cobj.size());
+ jobject jhandle =
+ JNativeHandle::MakeJavaNativeHandleObj(env, cobj.handle());
+
+ // We're sharing the handle of cobj, so the Java instance doesn't own it.
+ return env->NewObject(gFields.clazz,
+ gFields.constructor,
+ jname,
+ jsize,
+ jhandle,
+ false);
+}
+
+/* static */ std::unique_ptr<hardware::hidl_memory> JHidlMemory::javaToNative(
+ JNIEnv* env,
+ jobject jobj) {
+ jstring jname =
+ static_cast<jstring>(env->CallObjectMethod(jobj, gFields.getName));
+ jlong jsize = env->CallLongMethod(jobj, gFields.getSize);
+ jobject jhandle = env->CallObjectMethod(jobj, gFields.getHandle);
+
+ if (jsize > std::numeric_limits<size_t>::max()) {
+ return nullptr;
+ }
+
+ std::string cname = stringFromJava(env, jname);
+ size_t csize = jsize;
+ // We created the handle here, we're responsible to call
+ // native_handle_delete() on it. However, we don't assume ownership of the
+ // underlying fd, so we shouldn't call native_handle_close() on it.
+ native_handle_t* chandle = JNativeHandle::MakeCppNativeHandle(env, jhandle,
+ nullptr);
+ // hidl_memory doesn't take ownership of the handle here, so won't delete
+ // or close it.
+ return std::make_unique<hardware::hidl_memory>(cname, chandle, csize);
+}
+
+/* static */ JHidlMemory* JHidlMemory::getNativeContext(JNIEnv* env,
+ jobject jobj) {
+ env->MonitorEnter(jobj);
+ jlong jNativeContext = env->GetLongField(jobj, gFields.nativeContext);
+ JHidlMemory* native = reinterpret_cast<JHidlMemory*>(jNativeContext);
+ if (!native) {
+ native = new JHidlMemory();
+ env->SetLongField(jobj,
+ gFields.nativeContext,
+ reinterpret_cast<jlong>(native));
+ }
+ env->MonitorExit(jobj);
+ return native;
+}
+
+int register_android_os_HidlMemory(JNIEnv* env) {
+ jclass clazz = FindClassOrDie(env, CLASS_PATH);
+ gFields.clazz = MakeGlobalRefOrDie(env, clazz);
+
+ gFields.nativeContext = GetFieldIDOrDie(env, clazz, "mNativeContext", "J");
+
+ gFields.constructor = GetMethodIDOrDie(env,
+ clazz,
+ "<init>",
+ "(Ljava/lang/String;JL" PACKAGE_PATH "/NativeHandle;)V");
+ gFields.getName =
+ GetMethodIDOrDie(env, clazz, "getName", "()Ljava/lang/String;");
+ gFields.getSize = GetMethodIDOrDie(env, clazz, "getSize", "()J");
+ gFields.getHandle = GetMethodIDOrDie(env,
+ clazz,
+ "getHandle",
+ "()L" PACKAGE_PATH "/NativeHandle;");
+
+ RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods));
+
+ return 0;
+}
+
+} // namespace android
+
diff --git a/core/jni/android_os_HidlMemory.h b/core/jni/android_os_HidlMemory.h
new file mode 100644
index 0000000..993a132
--- /dev/null
+++ b/core/jni/android_os_HidlMemory.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2019 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_HIDL_MEMORY_H
+#define ANDROID_OS_HIDL_MEMORY_H
+
+#include <jni.h>
+#include <hidl/HidlSupport.h>
+
+namespace android {
+
+// A utility class for handling the android.os.HidlMemory class from JNI code.
+class JHidlMemory final {
+ public:
+ // Convert an android.os.HidlMemory object to its C++ counterpart,
+ // hardware::hidl_memory.
+ // No duplication of file descriptors is performed.
+ // The returned reference is owned by the underlying Java object.
+ // Returns nullptr if conversion cannot be done.
+ static const hardware::hidl_memory* fromJava(JNIEnv* env,
+ jobject jobj);
+
+ // Convert a hardware::hidl_memory object to its Java counterpart,
+ // android.os.HidlMemory.
+ // No duplication of file descriptors is performed.
+ // Returns nullptr if conversion cannot be done.
+ static jobject toJava(JNIEnv* env,
+ const hardware::hidl_memory& cobj);
+
+ ~JHidlMemory();
+
+ private:
+ // We store an instance of type JHidlMemory attached to every Java object
+ // of type HidlMemory, for holding any native context we need. This instance
+ // will get deleted when finalize() is called on the Java object.
+ // This method either extracts the native object from the Java object, or
+ // attached a new one if it doesn't yet exist.
+ static JHidlMemory* getNativeContext(JNIEnv* env, jobject obj);
+
+ // Convert an android.os.HidlMemory object to its C++ counterpart,
+ // hardware::hidl_memory.
+ // No duplication of file descriptors is performed.
+ // IMPORTANT: caller is responsible to native_handle_delete() the handle of the
+ // returned object. This is due to an underlying limitation of the hidl_handle
+ // type, where ownership of the handle implies ownership of the fd and we don't
+ // want the latter.
+ // Returns nullptr if conversion cannot be done.
+ static std::unique_ptr<hardware::hidl_memory> javaToNative(JNIEnv* env,
+ jobject jobj);
+
+ std::unique_ptr<hardware::hidl_memory> mObj;
+};
+
+int register_android_os_HidlMemory(JNIEnv* env);
+
+} // namespace android
+
+#endif //ANDROID_OS_HIDL_MEMORY_H
diff --git a/core/jni/android_os_HwBlob.cpp b/core/jni/android_os_HwBlob.cpp
index e5b72ca..0fb2911 100644
--- a/core/jni/android_os_HwBlob.cpp
+++ b/core/jni/android_os_HwBlob.cpp
@@ -340,6 +340,14 @@
return env->NewStringUTF(s->c_str());
}
+static jlong JHwBlob_native_getFieldHandle(JNIEnv* env,
+ jobject thiz,
+ jlong offset) {
+ sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
+
+ return reinterpret_cast<jlong>(blob->data()) + offset;
+}
+
#define DEFINE_BLOB_ARRAY_COPIER(Suffix,Type,NewType) \
static void JHwBlob_native_copyTo ## Suffix ## Array( \
JNIEnv *env, \
@@ -593,6 +601,7 @@
{ "getFloat", "(J)F", (void *)JHwBlob_native_getFloat },
{ "getDouble", "(J)D", (void *)JHwBlob_native_getDouble },
{ "getString", "(J)Ljava/lang/String;", (void *)JHwBlob_native_getString },
+ { "getFieldHandle", "(J)J", (void*) JHwBlob_native_getFieldHandle},
{ "copyToBoolArray", "(J[ZI)V", (void *)JHwBlob_native_copyToBoolArray },
{ "copyToInt8Array", "(J[BI)V", (void *)JHwBlob_native_copyToInt8Array },
diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp
index f437a78..151dbfc 100644
--- a/core/jni/android_os_HwParcel.cpp
+++ b/core/jni/android_os_HwParcel.cpp
@@ -20,6 +20,7 @@
#include "android_os_HwParcel.h"
+#include "android_os_HidlMemory.h"
#include "android_os_HwBinder.h"
#include "android_os_HwBlob.h"
#include "android_os_NativeHandle.h"
@@ -27,6 +28,8 @@
#include <nativehelper/JNIHelp.h>
#include <android_runtime/AndroidRuntime.h>
+#include <hidl/HidlBinderSupport.h>
+#include <hidl/HidlSupport.h>
#include <hidl/HidlTransportSupport.h>
#include <hidl/Status.h>
#include <nativehelper/ScopedLocalRef.h>
@@ -650,6 +653,36 @@
signalExceptionForError(env, err);
}
+static void JHwParcel_native_writeHidlMemory(
+ JNIEnv *env, jobject thiz, jobject jmem) {
+
+ if (jmem == nullptr) {
+ jniThrowException(env, "java/lang/NullPointerException", nullptr);
+ return;
+ }
+
+ status_t err = OK;
+
+ // Convert the Java object to its C++ counterpart.
+ const hardware::hidl_memory* cmem = JHidlMemory::fromJava(env, jmem);
+ if (cmem == nullptr) {
+ err = BAD_VALUE;
+ }
+
+ if (err == OK) {
+ // Write it to the parcel.
+ hardware::Parcel* parcel =
+ JHwParcel::GetNativeContext(env, thiz)->getParcel();
+
+ size_t parentHandle;
+ err = parcel->writeBuffer(cmem, sizeof(*cmem), &parentHandle);
+ if (err == OK) {
+ err = hardware::writeEmbeddedToParcel(*cmem, parcel, parentHandle, 0);
+ }
+ }
+ signalExceptionForError(env, err);
+}
+
static jstring MakeStringObjFromHidlString(JNIEnv *env, const hidl_string &s) {
String16 utf16String(s.c_str(), s.size());
@@ -877,6 +910,74 @@
return objArray;
}
+static status_t readEmbeddedHidlMemory(JNIEnv* env,
+ hardware::Parcel* parcel,
+ const hardware::hidl_memory& mem,
+ size_t parentHandle,
+ size_t parentOffset,
+ jobject* result) {
+ status_t err = hardware::readEmbeddedFromParcel(mem,
+ *parcel,
+ parentHandle,
+ parentOffset);
+ if (err == OK) {
+ // Convert to Java.
+ *result = JHidlMemory::toJava(env, mem);
+ if (*result == nullptr) {
+ err = BAD_VALUE;
+ }
+ }
+ return err;
+}
+
+static jobject JHwParcel_native_readHidlMemory(
+ JNIEnv* env, jobject thiz) {
+ hardware::Parcel* parcel =
+ JHwParcel::GetNativeContext(env, thiz)->getParcel();
+
+ jobject result = nullptr;
+
+ const hardware::hidl_memory* mem;
+ size_t parentHandle;
+
+ status_t err = parcel->readBuffer(sizeof(*mem),
+ &parentHandle,
+ reinterpret_cast<const void**>(&mem));
+ if (err == OK) {
+ err = readEmbeddedHidlMemory(env,
+ parcel,
+ *mem,
+ parentHandle,
+ 0,
+ &result);
+ }
+
+ signalExceptionForError(env, err);
+ return result;
+}
+
+static jobject JHwParcel_native_readEmbeddedHidlMemory(
+ JNIEnv* env,
+ jobject thiz,
+ jlong fieldHandle,
+ jlong parentHandle,
+ jlong offset) {
+ hardware::Parcel* parcel =
+ JHwParcel::GetNativeContext(env, thiz)->getParcel();
+
+ jobject result = nullptr;
+ const hardware::hidl_memory* mem =
+ reinterpret_cast<const hardware::hidl_memory*>(fieldHandle);
+ status_t err = readEmbeddedHidlMemory(env,
+ parcel,
+ *mem,
+ parentHandle,
+ offset,
+ &result);
+ signalExceptionForError(env, err);
+ return result;
+}
+
static jobject JHwParcel_native_readStrongBinder(JNIEnv *env, jobject thiz) {
hardware::Parcel *parcel =
JHwParcel::GetNativeContext(env, thiz)->getParcel();
@@ -1075,6 +1176,14 @@
{ "release", "()V",
(void *)JHwParcel_native_release },
+ {"writeHidlMemory", "(L" PACKAGE_PATH "/HidlMemory;)V",
+ (void*) JHwParcel_native_writeHidlMemory},
+
+ {"readHidlMemory", "()L" PACKAGE_PATH "/HidlMemory;",
+ (void*) JHwParcel_native_readHidlMemory},
+
+ {"readEmbeddedHidlMemory", "(JJJ)L" PACKAGE_PATH "/HidlMemory;",
+ (void*) JHwParcel_native_readEmbeddedHidlMemory},
};
namespace android {