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