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 {