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(int fileDescriptor)90 private SyncFence(int fileDescriptor) { 91 mNativePtr = nCreate(fileDescriptor); 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 {@link ParcelFileDescriptor}. By default, all 140 * method calls are delegated to the wrapped descriptor. This takes ownership of the 141 * {@link ParcelFileDescriptor}. 142 * 143 * @param wrapped The descriptor to be wrapped. 144 * @hide 145 */ create(@onNull ParcelFileDescriptor wrapped)146 public static @NonNull SyncFence create(@NonNull ParcelFileDescriptor wrapped) { 147 return new SyncFence(wrapped.detachFd()); 148 } 149 150 /** 151 * Create a new SyncFence wrapped around another descriptor. The returned {@link SyncFence} 152 * instance takes ownership of the file descriptor. 153 * 154 * @param fileDescriptor The descriptor to be wrapped. 155 * @hide 156 */ adopt(int fileDescriptor)157 public static @NonNull SyncFence adopt(int fileDescriptor) { 158 return new SyncFence(fileDescriptor); 159 } 160 161 /** 162 * Return a dup'd ParcelFileDescriptor from the SyncFence ParcelFileDescriptor. 163 * @hide 164 */ getFdDup()165 public @NonNull ParcelFileDescriptor getFdDup() throws IOException { 166 synchronized (mCloser) { 167 final int fd = mNativePtr != 0 ? nGetFd(mNativePtr) : -1; 168 if (fd == -1) { 169 throw new IllegalStateException("Cannot dup the FD of an invalid SyncFence"); 170 } 171 return ParcelFileDescriptor.fromFd(fd); 172 } 173 } 174 175 /** 176 * Checks if the SyncFile object is valid. 177 * 178 * @return {@code true} if the file descriptor represents a valid, open file; 179 * {@code false} otherwise. 180 */ isValid()181 public boolean isValid() { 182 synchronized (mCloser) { 183 return mNativePtr != 0 && nIsValid(mNativePtr); 184 } 185 } 186 187 /** 188 * Waits for a SyncFence to signal for up to the timeout duration. 189 * 190 * An invalid SyncFence, that is if {@link #isValid()} is false, is treated equivalently 191 * to a SyncFence that has already signaled. That is, wait() will immediately return true. 192 * 193 * @param timeout The timeout duration. If the duration is negative, then this waits forever. 194 * @return true if the fence signaled or isn't valid, false otherwise. 195 */ await(@onNull Duration timeout)196 public boolean await(@NonNull Duration timeout) { 197 final long timeoutNanos; 198 if (timeout.isNegative()) { 199 timeoutNanos = -1; 200 } else { 201 timeoutNanos = timeout.toNanos(); 202 } 203 return await(timeoutNanos); 204 } 205 206 /** 207 * Waits forever for a SyncFence to signal. 208 * 209 * An invalid SyncFence, that is if {@link #isValid()} is false, is treated equivalently 210 * to a SyncFence that has already signaled. That is, wait() will immediately return true. 211 * 212 * @return true if the fence signaled or isn't valid, false otherwise. 213 */ awaitForever()214 public boolean awaitForever() { 215 return await(-1); 216 } 217 await(long timeoutNanos)218 private boolean await(long timeoutNanos) { 219 synchronized (mCloser) { 220 return mNativePtr != 0 && nWait(mNativePtr, timeoutNanos); 221 } 222 } 223 224 /** 225 * Returns the time in nanoseconds that the fence signaled in the CLOCK_MONOTONIC time domain. 226 * This corresponds to {@link System#nanoTime()} but may also be compared to 227 * {@link SystemClock#uptimeMillis()} after adjusting for milliseconds vs. nanoseconds. 228 * 229 * If the fence isn't valid, that is if {@link #isValid()} is false, then this returns 230 * {@link #SIGNAL_TIME_INVALID}. Similarly, if an error occurs while trying to access the 231 * signal time, then {@link #SIGNAL_TIME_INVALID} is also returned. 232 * 233 * If the fence hasn't yet signaled, then {@link #SIGNAL_TIME_PENDING} is returned. 234 * 235 * @return The time the fence signaled, {@link #SIGNAL_TIME_INVALID} if there's an error, 236 * or {@link #SIGNAL_TIME_PENDING} if the fence hasn't signaled yet. 237 */ getSignalTime()238 public long getSignalTime() { 239 synchronized (mCloser) { 240 return mNativePtr != 0 ? nGetSignalTime(mNativePtr) : SIGNAL_TIME_INVALID; 241 } 242 } 243 244 /** 245 * Close the SyncFence. This implementation closes the underlying OS resources allocated 246 * this stream. 247 */ 248 @Override close()249 public void close() { 250 synchronized (mCloser) { 251 if (mNativePtr == 0) { 252 return; 253 } 254 mNativePtr = 0; 255 mCloser.run(); 256 } 257 } 258 259 @Override describeContents()260 public int describeContents() { 261 return CONTENTS_FILE_DESCRIPTOR; 262 } 263 264 /** @hide */ getLock()265 public Object getLock() { 266 return mCloser; 267 } 268 269 /** @hide */ getNativeFence()270 public long getNativeFence() { 271 return mNativePtr; 272 } 273 274 /** 275 * Flatten this object into a Parcel. 276 * 277 * @param out The Parcel in which the object should be written. 278 * @param flags Additional flags about how the object should be written. 279 * May be {@code 0} or {@link #PARCELABLE_WRITE_RETURN_VALUE} 280 */ 281 @Override writeToParcel(@onNull Parcel out, int flags)282 public void writeToParcel(@NonNull Parcel out, int flags) { 283 synchronized (mCloser) { 284 final int fd = mNativePtr != 0 ? nGetFd(mNativePtr) : -1; 285 if (fd == -1) { 286 out.writeBoolean(false); 287 } else { 288 out.writeBoolean(true); 289 FileDescriptor temp = new FileDescriptor(); 290 temp.setInt$(fd); 291 out.writeFileDescriptor(temp); 292 } 293 } 294 } 295 296 public static final @NonNull Parcelable.Creator<SyncFence> CREATOR = 297 new Parcelable.Creator<SyncFence>() { 298 @Override 299 public SyncFence createFromParcel(Parcel in) { 300 return new SyncFence(in); 301 } 302 303 @Override 304 public SyncFence[] newArray(int size) { 305 return new SyncFence[size]; 306 } 307 }; 308 nGetDestructor()309 private static native long nGetDestructor(); nCreate(int fd)310 private static native long nCreate(int fd); nIsValid(long nPtr)311 private static native boolean nIsValid(long nPtr); nGetFd(long nPtr)312 private static native int nGetFd(long nPtr); nWait(long nPtr, long timeout)313 private static native boolean nWait(long nPtr, long timeout); nGetSignalTime(long nPtr)314 private static native long nGetSignalTime(long nPtr); 315 } 316