• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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