Skip to content
This repository has been archived by the owner on Nov 8, 2023. It is now read-only.

Commit

Permalink
Implementing support for HIDL native handles in Java
Browse files Browse the repository at this point in the history
This change implements the equivalent of the C++ native_handle_t type in
Java. Similar to the C++ type, the NativeHandle class wraps an arraylist
of FileDescriptor objects, along with a raw data stream (integer array).

Bug: 35098567
Test: Ran m, hidl_test (C++ and Java). Functionality tests are included
in a separate CL.

Change-Id: Ic53f9a49ae17ce5708577a586230126ab0e222c7
  • Loading branch information
Nirav Atre authored and smore-lore committed Aug 13, 2018
1 parent bf66847 commit 9850dd9
Show file tree
Hide file tree
Showing 14 changed files with 718 additions and 98 deletions.
2 changes: 2 additions & 0 deletions Android.bp
Expand Up @@ -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",
],
Expand Down Expand Up @@ -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",
],
Expand Down
18 changes: 18 additions & 0 deletions api/system-current.txt
Expand Up @@ -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[]);
Expand All @@ -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();
Expand All @@ -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();
Expand All @@ -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>);
Expand Down Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions core/java/android/os/HwBlob.java
Expand Up @@ -232,6 +232,14 @@ public HwBlob(int size) {
* @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.
Expand Down
59 changes: 59 additions & 0 deletions core/java/android/os/HwParcel.java
Expand Up @@ -115,6 +115,13 @@ public 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.
Expand Down Expand Up @@ -159,6 +166,11 @@ public 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.
Expand Down Expand Up @@ -266,6 +278,14 @@ public final void writeStringVector(ArrayList<String> val) {
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
Expand Down Expand Up @@ -328,6 +348,30 @@ public final void writeStringVector(ArrayList<String> val) {
* @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.
Expand Down Expand Up @@ -377,6 +421,12 @@ public final void writeStringVector(ArrayList<String> val) {
* @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.
Expand Down Expand Up @@ -464,6 +514,15 @@ public final ArrayList<String> readStringVector() {
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
Expand Down
191 changes: 191 additions & 0 deletions core/java/android/os/NativeHandle.java
@@ -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;
}
}
1 change: 1 addition & 0 deletions core/jni/Android.bp
Expand Up @@ -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",
Expand Down

0 comments on commit 9850dd9

Please sign in to comment.