summaryrefslogtreecommitdiff
path: root/core/java/android/hardware/SyncFence.java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/hardware/SyncFence.java')
-rw-r--r--core/java/android/hardware/SyncFence.java183
1 files changed, 150 insertions, 33 deletions
diff --git a/core/java/android/hardware/SyncFence.java b/core/java/android/hardware/SyncFence.java
index b0a6f51c2a39..693cda7720e4 100644
--- a/core/java/android/hardware/SyncFence.java
+++ b/core/java/android/hardware/SyncFence.java
@@ -17,12 +17,17 @@
package android.hardware;
import android.annotation.NonNull;
+import android.opengl.EGLDisplay;
+import android.opengl.EGLSync;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
-import java.io.Closeable;
+import libcore.util.NativeAllocationRegistry;
+
+import java.io.FileDescriptor;
import java.io.IOException;
+import java.time.Duration;
/**
* A SyncFence represents a synchronization primitive which signals when hardware buffers have
@@ -34,19 +39,57 @@ import java.io.IOException;
* Once the fence signals, then the backing storage for the framebuffer may be safely read from,
* such as for display or for media encoding.</p>
*
- * @see <a href="https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkCreateFence.html">
- * VkFence</a>
+ * @see android.opengl.EGLExt#eglDupNativeFenceFDANDROID(EGLDisplay, EGLSync)
+ * @see android.media.Image#getFence()
*/
-public final class SyncFence implements Closeable, Parcelable {
- private static final String TAG = "SyncFence";
+public final class SyncFence implements AutoCloseable, Parcelable {
+
+ /**
+ * An invalid signal time. Represents either the signal time for a SyncFence that isn't valid
+ * (that is, {@link #isValid()} is false), or if an error occurred while attempting to retrieve
+ * the signal time.
+ */
+ public static final long SIGNAL_TIME_INVALID = -1;
/**
- * Wrapped {@link android.os.ParcelFileDescriptor}.
+ * A pending signal time. This is equivalent to the max value of a long, representing an
+ * infinitely far point in the future.
*/
- private ParcelFileDescriptor mWrapped;
+ public static final long SIGNAL_TIME_PENDING = Long.MAX_VALUE;
+
+ private static final NativeAllocationRegistry sRegistry =
+ NativeAllocationRegistry.createNonmalloced(SyncFence.class.getClassLoader(),
+ nGetDestructor(), 4);
+
+ private long mNativePtr;
+
+ // The destructor for this object
+ // This is also used as our internal lock object. Although SyncFence doesn't claim to be
+ // thread-safe, the cost of doing so to avoid issues around double-close or similar issues
+ // is well worth making.
+ private final Runnable mCloser;
private SyncFence(@NonNull ParcelFileDescriptor wrapped) {
- mWrapped = wrapped;
+ mNativePtr = nCreate(wrapped.detachFd());
+ mCloser = sRegistry.registerNativeAllocation(this, mNativePtr);
+ }
+
+ private SyncFence(@NonNull Parcel parcel) {
+ boolean valid = parcel.readBoolean();
+ FileDescriptor fileDescriptor = null;
+ if (valid) {
+ fileDescriptor = parcel.readRawFileDescriptor();
+ }
+ if (fileDescriptor != null) {
+ mNativePtr = nCreate(fileDescriptor.getInt$());
+ mCloser = sRegistry.registerNativeAllocation(this, mNativePtr);
+ } else {
+ mCloser = () -> {};
+ }
+ }
+
+ private SyncFence() {
+ mCloser = () -> {};
}
/***
@@ -56,7 +99,7 @@ public final class SyncFence implements Closeable, Parcelable {
* @hide
*/
public static @NonNull SyncFence createEmpty() {
- return new SyncFence(ParcelFileDescriptor.adoptFd(-1));
+ return new SyncFence();
}
/**
@@ -75,7 +118,13 @@ public final class SyncFence implements Closeable, Parcelable {
* @hide
*/
public @NonNull ParcelFileDescriptor getFdDup() throws IOException {
- return mWrapped.dup();
+ synchronized (mCloser) {
+ final int fd = mNativePtr != 0 ? nGetFd(mNativePtr) : -1;
+ if (fd == -1) {
+ throw new IllegalStateException("Cannot dup the FD of an invalid SyncFence");
+ }
+ return ParcelFileDescriptor.fromFd(fd);
+ }
}
/**
@@ -85,29 +134,84 @@ public final class SyncFence implements Closeable, Parcelable {
* {@code false} otherwise.
*/
public boolean isValid() {
- return mWrapped.getFileDescriptor().valid();
+ synchronized (mCloser) {
+ return mNativePtr != 0 && nIsValid(mNativePtr);
+ }
+ }
+
+ /**
+ * Waits for a SyncFence to signal for up to the timeout duration.
+ *
+ * An invalid SyncFence, that is if {@link #isValid()} is false, is treated equivalently
+ * to a SyncFence that has already signaled. That is, wait() will immediately return true.
+ *
+ * @param timeout The timeout duration. If the duration is negative, then this waits forever.
+ * @return true if the fence signaled or isn't valid, false otherwise.
+ */
+ public boolean await(@NonNull Duration timeout) {
+ final long timeoutNanos;
+ if (timeout.isNegative()) {
+ timeoutNanos = -1;
+ } else {
+ timeoutNanos = timeout.toNanos();
+ }
+ return await(timeoutNanos);
+ }
+
+ /**
+ * Waits forever for a SyncFence to signal.
+ *
+ * An invalid SyncFence, that is if {@link #isValid()} is false, is treated equivalently
+ * to a SyncFence that has already signaled. That is, wait() will immediately return true.
+ *
+ * @return true if the fence signaled or isn't valid, false otherwise.
+ */
+ public boolean awaitForever() {
+ return await(-1);
+ }
+
+ private boolean await(long timeoutNanos) {
+ synchronized (mCloser) {
+ return mNativePtr != 0 && nWait(mNativePtr, timeoutNanos);
+ }
+ }
+
+ /**
+ * Returns the time that the fence signaled in the CLOCK_MONOTONIC time domain.
+ *
+ * If the fence isn't valid, that is if {@link #isValid()} is false, then this returns
+ * {@link #SIGNAL_TIME_INVALID}. Similarly, if an error occurs while trying to access the
+ * signal time, then {@link #SIGNAL_TIME_INVALID} is also returned.
+ *
+ * If the fence hasn't yet signaled, then {@link #SIGNAL_TIME_PENDING} is returned.
+ *
+ * @return The time the fence signaled, {@link #SIGNAL_TIME_INVALID} if there's an error,
+ * or {@link #SIGNAL_TIME_PENDING} if the fence hasn't signaled yet.
+ */
+ public long getSignalTime() {
+ synchronized (mCloser) {
+ return mNativePtr != 0 ? nGetSignalTime(mNativePtr) : SIGNAL_TIME_INVALID;
+ }
}
/**
* Close the SyncFence. This implementation closes the underlying OS resources allocated
* this stream.
- *
- * @throws IOException If an error occurs attempting to close this SyncFence.
*/
@Override
- public void close() throws IOException {
- if (mWrapped != null) {
- try {
- mWrapped.close();
- } finally {
- // success
+ public void close() {
+ synchronized (mCloser) {
+ if (mNativePtr == 0) {
+ return;
}
+ mNativePtr = 0;
+ mCloser.run();
}
}
@Override
public int describeContents() {
- return mWrapped.describeContents();
+ return CONTENTS_FILE_DESCRIPTOR;
}
/**
@@ -119,23 +223,36 @@ public final class SyncFence implements Closeable, Parcelable {
*/
@Override
public void writeToParcel(@NonNull Parcel out, int flags) {
- try {
- mWrapped.writeToParcel(out, flags);
- } finally {
- // success
+ synchronized (mCloser) {
+ final int fd = mNativePtr != 0 ? nGetFd(mNativePtr) : -1;
+ if (fd == -1) {
+ out.writeBoolean(false);
+ } else {
+ out.writeBoolean(true);
+ FileDescriptor temp = new FileDescriptor();
+ temp.setInt$(fd);
+ out.writeFileDescriptor(temp);
+ }
}
}
public static final @NonNull Parcelable.Creator<SyncFence> CREATOR =
new Parcelable.Creator<SyncFence>() {
- @Override
- public SyncFence createFromParcel(Parcel in) {
- return new SyncFence(ParcelFileDescriptor.CREATOR.createFromParcel(in));
- }
+ @Override
+ public SyncFence createFromParcel(Parcel in) {
+ return new SyncFence(in);
+ }
- @Override
- public SyncFence[] newArray(int size) {
- return new SyncFence[size];
- }
- };
+ @Override
+ public SyncFence[] newArray(int size) {
+ return new SyncFence[size];
+ }
+ };
+
+ private static native long nGetDestructor();
+ private static native long nCreate(int fd);
+ private static native boolean nIsValid(long nPtr);
+ private static native int nGetFd(long nPtr);
+ private static native boolean nWait(long nPtr, long timeout);
+ private static native long nGetSignalTime(long nPtr);
}