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