1 /** 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.hardware; 18 19 import android.annotation.NonNull; 20 import android.media.Image; 21 import android.media.ImageWriter; 22 import android.opengl.EGLDisplay; 23 import android.opengl.EGLSync; 24 import android.os.Parcel; 25 import android.os.ParcelFileDescriptor; 26 import android.os.Parcelable; 27 import android.os.SystemClock; 28 29 import libcore.util.NativeAllocationRegistry; 30 31 import java.io.FileDescriptor; 32 import java.io.IOException; 33 import java.time.Duration; 34 35 /** 36 * A SyncFence represents a synchronization primitive which signals when hardware units have 37 * completed work on a particular resource. They initially start in an unsignaled state and make 38 * a one-time transition to either a signaled or error state. SyncFences are created by various 39 * device APIs in response to submitting tasks to the device. They cannot be created nor signaled 40 * by userspace. As a result, this means that a SyncFence will make always make forward progress. 41 * 42 * <p>SyncFence's generally come in one of two varieties. "Presentation fences" refer to 43 * a SyncFence when the writing to a buffer has finished. "Release fences" then refer 44 * to when the reading from a buffer has finished.</p> 45 * 46 * <p>For example, a GPU rendering to a framebuffer may generate a synchronization fence, 47 * e.g., an EGLSync or VkFence, which signals when rendering has completed. Once the fence signals, 48 * then the backing storage for the framebuffer may be safely read from, such as for display or 49 * for media encoding. This would be referred to as a "presentation fence."</p> 50 * 51 * <p>Similarly when using an {@link android.media.ImageWriter} it is possible that an 52 * {@link android.media.Image} returned by {@link ImageWriter#dequeueInputImage()} may already 53 * have a {@link Image#getFence() fence} set on it. This would be what is referred to as either 54 * a "release fence" or an "acqurie fence" and indicates the fence that the writer must wait 55 * on before writing to the underlying buffer. In the case of ImageWriter this is done 56 * automatically when eg {@link Image#getPlanes()} is called, however when using 57 * {@link Image#getHardwareBuffer()} it is the caller's responsibility to ensure the 58 * release fence has signaled before writing to the buffer.</p> 59 * 60 * @see android.opengl.EGLExt#eglDupNativeFenceFDANDROID(EGLDisplay, EGLSync) 61 * @see android.media.Image#getFence() 62 */ 63 public final class SyncFence implements AutoCloseable, Parcelable { 64 65 /** 66 * An invalid signal time. Represents either the signal time for a SyncFence that isn't valid 67 * (that is, {@link #isValid()} is false), or if an error occurred while attempting to retrieve 68 * the signal time. 69 */ 70 public static final long SIGNAL_TIME_INVALID = -1; 71 72 /** 73 * A pending signal time. This is equivalent to the max value of a long, representing an 74 * infinitely far point in the future. 75 */ 76 public static final long SIGNAL_TIME_PENDING = Long.MAX_VALUE; 77 78 private static final NativeAllocationRegistry sRegistry = 79 NativeAllocationRegistry.createNonmalloced(SyncFence.class.getClassLoader(), 80 nGetDestructor(), 4); 81 82 private long mNativePtr; 83 84 // The destructor for this object 85 // This is also used as our internal lock object. Although SyncFence doesn't claim to be 86 // thread-safe, the cost of doing so to avoid issues around double-close or similar issues 87 // is well worth making. 88 private final Runnable mCloser; 89 SyncFence(@onNull ParcelFileDescriptor wrapped)90 private SyncFence(@NonNull ParcelFileDescriptor wrapped) { 91 mNativePtr = nCreate(wrapped.detachFd()); 92 mCloser = sRegistry.registerNativeAllocation(this, mNativePtr); 93 } 94 SyncFence(@onNull Parcel parcel)95 private SyncFence(@NonNull Parcel parcel) { 96 boolean valid = parcel.readBoolean(); 97 FileDescriptor fileDescriptor = null; 98 if (valid) { 99 fileDescriptor = parcel.readRawFileDescriptor(); 100 } 101 if (fileDescriptor != null) { 102 mNativePtr = nCreate(fileDescriptor.getInt$()); 103 mCloser = sRegistry.registerNativeAllocation(this, mNativePtr); 104 } else { 105 mCloser = () -> {}; 106 } 107 } 108 109 /** 110 * Creates a SyncFence from a libui Fence* 111 * DOES NOT TAKE AN ADDITIONAL REFERENCE, the caller must incref if it intends to retain 112 * ownership (eg, when using sp<Fence>) 113 * @hide 114 */ SyncFence(long nativeFencePtr)115 public SyncFence(long nativeFencePtr) { 116 mNativePtr = nativeFencePtr; 117 if (nativeFencePtr != 0) { 118 mCloser = sRegistry.registerNativeAllocation(this, mNativePtr); 119 } else { 120 mCloser = () -> {}; 121 } 122 } 123 SyncFence()124 private SyncFence() { 125 mCloser = () -> {}; 126 } 127 128 /*** 129 * Create an empty SyncFence 130 * 131 * @return a SyncFence with invalid fence 132 * @hide 133 */ createEmpty()134 public static @NonNull SyncFence createEmpty() { 135 return new SyncFence(); 136 } 137 138 /** 139 * Create a new SyncFence wrapped around another descriptor. By default, all method calls are 140 * delegated to the wrapped descriptor. 141 * 142 * @param wrapped The descriptor to be wrapped. 143 * @hide 144 */ create(@onNull ParcelFileDescriptor wrapped)145 public static @NonNull SyncFence create(@NonNull ParcelFileDescriptor wrapped) { 146 return new SyncFence(wrapped); 147 } 148 149 /** 150 * Return a dup'd ParcelFileDescriptor from the SyncFence ParcelFileDescriptor. 151 * @hide 152 */ getFdDup()153 public @NonNull ParcelFileDescriptor getFdDup() throws IOException { 154 synchronized (mCloser) { 155 final int fd = mNativePtr != 0 ? nGetFd(mNativePtr) : -1; 156 if (fd == -1) { 157 throw new IllegalStateException("Cannot dup the FD of an invalid SyncFence"); 158 } 159 return ParcelFileDescriptor.fromFd(fd); 160 } 161 } 162 163 /** 164 * Checks if the SyncFile object is valid. 165 * 166 * @return {@code true} if the file descriptor represents a valid, open file; 167 * {@code false} otherwise. 168 */ isValid()169 public boolean isValid() { 170 synchronized (mCloser) { 171 return mNativePtr != 0 && nIsValid(mNativePtr); 172 } 173 } 174 175 /** 176 * Waits for a SyncFence to signal for up to the timeout duration. 177 * 178 * An invalid SyncFence, that is if {@link #isValid()} is false, is treated equivalently 179 * to a SyncFence that has already signaled. That is, wait() will immediately return true. 180 * 181 * @param timeout The timeout duration. If the duration is negative, then this waits forever. 182 * @return true if the fence signaled or isn't valid, false otherwise. 183 */ await(@onNull Duration timeout)184 public boolean await(@NonNull Duration timeout) { 185 final long timeoutNanos; 186 if (timeout.isNegative()) { 187 timeoutNanos = -1; 188 } else { 189 timeoutNanos = timeout.toNanos(); 190 } 191 return await(timeoutNanos); 192 } 193 194 /** 195 * Waits forever for a SyncFence to signal. 196 * 197 * An invalid SyncFence, that is if {@link #isValid()} is false, is treated equivalently 198 * to a SyncFence that has already signaled. That is, wait() will immediately return true. 199 * 200 * @return true if the fence signaled or isn't valid, false otherwise. 201 */ awaitForever()202 public boolean awaitForever() { 203 return await(-1); 204 } 205 await(long timeoutNanos)206 private boolean await(long timeoutNanos) { 207 synchronized (mCloser) { 208 return mNativePtr != 0 && nWait(mNativePtr, timeoutNanos); 209 } 210 } 211 212 /** 213 * Returns the time in nanoseconds that the fence signaled in the CLOCK_MONOTONIC time domain. 214 * This corresponds to {@link System#nanoTime()} but may also be compared to 215 * {@link SystemClock#uptimeMillis()} after adjusting for milliseconds vs. nanoseconds. 216 * 217 * If the fence isn't valid, that is if {@link #isValid()} is false, then this returns 218 * {@link #SIGNAL_TIME_INVALID}. Similarly, if an error occurs while trying to access the 219 * signal time, then {@link #SIGNAL_TIME_INVALID} is also returned. 220 * 221 * If the fence hasn't yet signaled, then {@link #SIGNAL_TIME_PENDING} is returned. 222 * 223 * @return The time the fence signaled, {@link #SIGNAL_TIME_INVALID} if there's an error, 224 * or {@link #SIGNAL_TIME_PENDING} if the fence hasn't signaled yet. 225 */ getSignalTime()226 public long getSignalTime() { 227 synchronized (mCloser) { 228 return mNativePtr != 0 ? nGetSignalTime(mNativePtr) : SIGNAL_TIME_INVALID; 229 } 230 } 231 232 /** 233 * Close the SyncFence. This implementation closes the underlying OS resources allocated 234 * this stream. 235 */ 236 @Override close()237 public void close() { 238 synchronized (mCloser) { 239 if (mNativePtr == 0) { 240 return; 241 } 242 mNativePtr = 0; 243 mCloser.run(); 244 } 245 } 246 247 @Override describeContents()248 public int describeContents() { 249 return CONTENTS_FILE_DESCRIPTOR; 250 } 251 252 /** @hide */ getLock()253 public Object getLock() { 254 return mCloser; 255 } 256 257 /** @hide */ getNativeFence()258 public long getNativeFence() { 259 return mNativePtr; 260 } 261 262 /** 263 * Flatten this object into a Parcel. 264 * 265 * @param out The Parcel in which the object should be written. 266 * @param flags Additional flags about how the object should be written. 267 * May be {@code 0} or {@link #PARCELABLE_WRITE_RETURN_VALUE} 268 */ 269 @Override writeToParcel(@onNull Parcel out, int flags)270 public void writeToParcel(@NonNull Parcel out, int flags) { 271 synchronized (mCloser) { 272 final int fd = mNativePtr != 0 ? nGetFd(mNativePtr) : -1; 273 if (fd == -1) { 274 out.writeBoolean(false); 275 } else { 276 out.writeBoolean(true); 277 FileDescriptor temp = new FileDescriptor(); 278 temp.setInt$(fd); 279 out.writeFileDescriptor(temp); 280 } 281 } 282 } 283 284 public static final @NonNull Parcelable.Creator<SyncFence> CREATOR = 285 new Parcelable.Creator<SyncFence>() { 286 @Override 287 public SyncFence createFromParcel(Parcel in) { 288 return new SyncFence(in); 289 } 290 291 @Override 292 public SyncFence[] newArray(int size) { 293 return new SyncFence[size]; 294 } 295 }; 296 nGetDestructor()297 private static native long nGetDestructor(); nCreate(int fd)298 private static native long nCreate(int fd); nIsValid(long nPtr)299 private static native boolean nIsValid(long nPtr); nGetFd(long nPtr)300 private static native int nGetFd(long nPtr); nWait(long nPtr, long timeout)301 private static native boolean nWait(long nPtr, long timeout); nGetSignalTime(long nPtr)302 private static native long nGetSignalTime(long nPtr); 303 } 304