Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9850dd97 authored by Nirav Atre's avatar Nirav Atre Committed by Steven Moreland
Browse files

Implementing support for HIDL native handles in Java

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
parent bf668472
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -898,6 +898,7 @@ java_library {
        "core/java/android/os/IHwInterface.java",
        "core/java/android/os/DeadObjectException.java",
        "core/java/android/os/DeadSystemException.java",
        "core/java/android/os/NativeHandle.java",
        "core/java/android/os/RemoteException.java",
        "core/java/android/util/AndroidException.java",
    ],
@@ -1444,6 +1445,7 @@ droiddoc {
        "core/java/android/os/IHwInterface.java",
        "core/java/android/os/DeadObjectException.java",
        "core/java/android/os/DeadSystemException.java",
        "core/java/android/os/NativeHandle.java",
        "core/java/android/os/RemoteException.java",
        "core/java/android/util/AndroidException.java",
    ],
+18 −0
Original line number Diff line number Diff line
@@ -3726,6 +3726,7 @@ package android.os {
    method public final void putInt64Array(long, long[]);
    method public final void putInt8(long, byte);
    method public final void putInt8Array(long, byte[]);
    method public final void putNativeHandle(long, android.os.NativeHandle);
    method public final void putString(long, java.lang.String);
    method public static java.lang.Boolean[] wrapArray(boolean[]);
    method public static java.lang.Long[] wrapArray(long[]);
@@ -3745,6 +3746,7 @@ package android.os {
    method public final double readDouble();
    method public final java.util.ArrayList<java.lang.Double> readDoubleVector();
    method public final android.os.HwBlob readEmbeddedBuffer(long, long, long, boolean);
    method public final android.os.NativeHandle readEmbeddedNativeHandle(long, long);
    method public final float readFloat();
    method public final java.util.ArrayList<java.lang.Float> readFloatVector();
    method public final short readInt16();
@@ -3755,6 +3757,8 @@ package android.os {
    method public final java.util.ArrayList<java.lang.Long> readInt64Vector();
    method public final byte readInt8();
    method public final java.util.ArrayList<java.lang.Byte> readInt8Vector();
    method public final android.os.NativeHandle readNativeHandle();
    method public final java.util.ArrayList<android.os.NativeHandle> readNativeHandleVector();
    method public final java.lang.String readString();
    method public final java.util.ArrayList<java.lang.String> readStringVector();
    method public final android.os.IHwBinder readStrongBinder();
@@ -3778,6 +3782,8 @@ package android.os {
    method public final void writeInt8(byte);
    method public final void writeInt8Vector(java.util.ArrayList<java.lang.Byte>);
    method public final void writeInterfaceToken(java.lang.String);
    method public final void writeNativeHandle(android.os.NativeHandle);
    method public final void writeNativeHandleVector(java.util.ArrayList<android.os.NativeHandle>);
    method public final void writeStatus(int);
    method public final void writeString(java.lang.String);
    method public final void writeStringVector(java.util.ArrayList<java.lang.String>);
@@ -3822,6 +3828,18 @@ package android.os {
    field public static final android.os.Parcelable.Creator<android.os.IncidentReportArgs> CREATOR;
  }

  public final class NativeHandle implements java.io.Closeable {
    ctor public NativeHandle();
    ctor public NativeHandle(java.io.FileDescriptor, boolean);
    ctor public NativeHandle(java.io.FileDescriptor[], int[], boolean);
    method public void close() throws java.io.IOException;
    method public android.os.NativeHandle dup() throws java.io.IOException;
    method public java.io.FileDescriptor getFileDescriptor();
    method public java.io.FileDescriptor[] getFileDescriptors();
    method public int[] getInts();
    method public boolean hasSingleFileDescriptor();
  }

  public final class PowerManager {
    method public void userActivity(long, int, int);
    field public static final int USER_ACTIVITY_EVENT_ACCESSIBILITY = 3; // 0x3
+8 −0
Original line number Diff line number Diff line
@@ -232,6 +232,14 @@ public class HwBlob {
     * @throws IndexOutOfBoundsException when [offset, offset + sizeof(jstring)] is out of range
     */
    public native final void putString(long offset, String x);
    /**
     * Writes a native handle (without duplicating the underlying file descriptors) at an offset.
     *
     * @param offset location to write value
     * @param x a {@link NativeHandle} instance to write
     * @throws IndexOutOfBoundsException when [offset, offset + sizeof(jobject)] is out of range
     */
    public native final void putNativeHandle(long offset, NativeHandle x);

    /**
     * Put a boolean array contiguously at an offset in the blob.
+59 −0
Original line number Diff line number Diff line
@@ -115,6 +115,13 @@ public class HwParcel {
     * @param val to write
     */
    public native final void writeString(String val);
    /**
     * Writes a native handle (without duplicating the underlying
     * file descriptors) to the end of the parcel.
     *
     * @param val to write
     */
    public native final void writeNativeHandle(NativeHandle val);

    /**
     * Writes an array of boolean values to the end of the parcel.
@@ -159,6 +166,11 @@ public class HwParcel {
     * @param val to write
     */
    private native final void writeStringVector(String[] val);
    /**
     * Writes an array of native handles to the end of the parcel.
     * @param val array of {@link NativeHandle} objects to write
     */
    private native final void writeNativeHandleVector(NativeHandle[] val);

    /**
     * Helper method to write a list of Booleans to val.
@@ -266,6 +278,14 @@ public class HwParcel {
        writeStringVector(val.toArray(new String[val.size()]));
    }

    /**
     * Helper method to write a list of native handles to the end of the parcel.
     * @param val list of {@link NativeHandle} objects to write
     */
    public final void writeNativeHandleVector(ArrayList<NativeHandle> val) {
        writeNativeHandleVector(val.toArray(new NativeHandle[val.size()]));
    }

    /**
     * Write a hwbinder object to the end of the parcel.
     * @param binder value to write
@@ -328,6 +348,30 @@ public class HwParcel {
     * @throws IllegalArgumentException if the parcel has no more data
     */
    public native final String readString();
    /**
     * Reads a native handle (without duplicating the underlying file
     * descriptors) from the parcel. These file descriptors will only
     * be open for the duration that the binder window is open. If they
     * are needed further, you must call {@link NativeHandle#dup()}.
     *
     * @return a {@link NativeHandle} instance parsed from the parcel
     * @throws IllegalArgumentException if the parcel has no more data
     */
    public native final NativeHandle readNativeHandle();
    /**
     * Reads an embedded native handle (without duplicating the underlying
     * file descriptors) from the parcel. These file descriptors will only
     * be open for the duration that the binder window is open. If they
     * are needed further, you must call {@link NativeHandle#dup()}. You
     * do not need to call close on the NativeHandle returned from this.
     *
     * @param parentHandle handle from which to read the embedded object
     * @param offset offset into parent
     * @return a {@link NativeHandle} instance parsed from the parcel
     * @throws IllegalArgumentException if the parcel has no more data
     */
    public native final NativeHandle readEmbeddedNativeHandle(
            long parentHandle, long offset);

    /**
     * Reads an array of boolean values from the parcel.
@@ -377,6 +421,12 @@ public class HwParcel {
     * @throws IllegalArgumentException if the parcel has no more data
     */
    private native final String[] readStringVectorAsArray();
    /**
     * Reads an array of native handles from the parcel.
     * @return array of {@link NativeHandle} objects
     * @throws IllegalArgumentException if the parcel has no more data
     */
    private native final NativeHandle[] readNativeHandleAsArray();

    /**
     * Convenience method to read a Boolean vector as an ArrayList.
@@ -464,6 +514,15 @@ public class HwParcel {
        return new ArrayList<String>(Arrays.asList(readStringVectorAsArray()));
    }

    /**
     * Convenience method to read a vector of native handles as an ArrayList.
     * @return array of {@link NativeHandle} objects.
     * @throws IllegalArgumentException if the parcel has no more data
     */
    public final ArrayList<NativeHandle> readNativeHandleVector() {
        return new ArrayList<NativeHandle>(Arrays.asList(readNativeHandleAsArray()));
    }

    /**
     * Reads a strong binder value from the parcel.
     * @return binder object read from parcel or null if no binder can be read
+191 −0
Original line number Diff line number Diff line
/*
 * 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;
    }
}
Loading