• 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.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