1 /*
2  * Copyright (C) 2006 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.os;
18 
19 import static android.system.OsConstants.AF_UNIX;
20 import static android.system.OsConstants.F_DUPFD;
21 import static android.system.OsConstants.F_DUPFD_CLOEXEC;
22 import static android.system.OsConstants.O_CLOEXEC;
23 import static android.system.OsConstants.SEEK_SET;
24 import static android.system.OsConstants.SOCK_CLOEXEC;
25 import static android.system.OsConstants.SOCK_SEQPACKET;
26 import static android.system.OsConstants.SOCK_STREAM;
27 import static android.system.OsConstants.S_IROTH;
28 import static android.system.OsConstants.S_IRWXG;
29 import static android.system.OsConstants.S_IRWXU;
30 import static android.system.OsConstants.S_ISLNK;
31 import static android.system.OsConstants.S_ISREG;
32 import static android.system.OsConstants.S_IWOTH;
33 
34 import android.annotation.NonNull;
35 import android.annotation.SuppressLint;
36 import android.annotation.TestApi;
37 import android.compat.annotation.UnsupportedAppUsage;
38 import android.content.BroadcastReceiver;
39 import android.content.ContentProvider;
40 import android.content.ContentResolver;
41 import android.net.Uri;
42 import android.os.MessageQueue.OnFileDescriptorEventListener;
43 import android.ravenwood.annotation.RavenwoodKeepWholeClass;
44 import android.ravenwood.annotation.RavenwoodNativeSubstitutionClass;
45 import android.ravenwood.annotation.RavenwoodReplace;
46 import android.ravenwood.annotation.RavenwoodThrow;
47 import android.system.ErrnoException;
48 import android.system.Os;
49 import android.system.OsConstants;
50 import android.system.StructStat;
51 import android.util.CloseGuard;
52 import android.util.Log;
53 import android.util.Slog;
54 
55 import com.android.internal.ravenwood.RavenwoodEnvironment;
56 
57 import dalvik.system.VMRuntime;
58 
59 import libcore.io.IoUtils;
60 import libcore.io.Memory;
61 
62 import java.io.Closeable;
63 import java.io.File;
64 import java.io.FileDescriptor;
65 import java.io.FileInputStream;
66 import java.io.FileNotFoundException;
67 import java.io.FileOutputStream;
68 import java.io.IOException;
69 import java.io.InterruptedIOException;
70 import java.io.UncheckedIOException;
71 import java.net.DatagramSocket;
72 import java.net.Socket;
73 import java.nio.ByteOrder;
74 
75 /**
76  * The FileDescriptor returned by {@link Parcel#readFileDescriptor}, allowing
77  * you to close it when done with it.
78  */
79 @RavenwoodKeepWholeClass
80 @RavenwoodNativeSubstitutionClass(
81         "com.android.platform.test.ravenwood.nativesubstitution.ParcelFileDescriptor_host")
82 public class ParcelFileDescriptor implements Parcelable, Closeable {
83     private static final String TAG = "ParcelFileDescriptor";
84 
85     private final FileDescriptor mFd;
86 
87     /**
88      * Optional socket used to communicate close events, status at close, and
89      * detect remote process crashes.
90      */
91     private FileDescriptor mCommFd;
92 
93     /**
94      * Wrapped {@link ParcelFileDescriptor}, if any. Used to avoid
95      * double-closing {@link #mFd}.
96      * mClosed is always true if mWrapped is non-null.
97      */
98     private final ParcelFileDescriptor mWrapped;
99 
100     /**
101      * Maximum {@link #mStatusBuf} size; longer status messages will be
102      * truncated.
103      */
104     private static final int MAX_STATUS = 1024;
105 
106     /**
107      * Temporary buffer used by {@link #readCommStatus(FileDescriptor, byte[])},
108      * allocated on-demand.
109      */
110     private byte[] mStatusBuf;
111 
112     /**
113      * Status read by {@link #checkError()}, or null if not read yet.
114      */
115     private Status mStatus;
116 
117     private volatile boolean mClosed;
118 
119     private final CloseGuard mGuard = CloseGuard.get();
120 
121     /**
122      * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied and
123      * this file doesn't already exist, then create the file with permissions
124      * such that any application can read it.
125      *
126      * @deprecated Creating world-readable files is very dangerous, and likely
127      *             to cause security holes in applications. It is strongly
128      *             discouraged; instead, applications should use more formal
129      *             mechanism for interactions such as {@link ContentProvider},
130      *             {@link BroadcastReceiver}, and {@link android.app.Service}.
131      *             There are no guarantees that this access mode will remain on
132      *             a file, such as when it goes through a backup and restore.
133      */
134     @Deprecated
135     public static final int MODE_WORLD_READABLE = 0x00000001;
136 
137     /**
138      * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied and
139      * this file doesn't already exist, then create the file with permissions
140      * such that any application can write it.
141      *
142      * @deprecated Creating world-writable files is very dangerous, and likely
143      *             to cause security holes in applications. It is strongly
144      *             discouraged; instead, applications should use more formal
145      *             mechanism for interactions such as {@link ContentProvider},
146      *             {@link BroadcastReceiver}, and {@link android.app.Service}.
147      *             There are no guarantees that this access mode will remain on
148      *             a file, such as when it goes through a backup and restore.
149      */
150     @Deprecated
151     public static final int MODE_WORLD_WRITEABLE = 0x00000002;
152 
153     /**
154      * For use with {@link #open}: open the file with read-only access.
155      */
156     public static final int MODE_READ_ONLY = 0x10000000;
157 
158     /**
159      * For use with {@link #open}: open the file with write-only access.
160      */
161     public static final int MODE_WRITE_ONLY = 0x20000000;
162 
163     /**
164      * For use with {@link #open}: open the file with read and write access.
165      */
166     public static final int MODE_READ_WRITE = 0x30000000;
167 
168     /**
169      * For use with {@link #open}: create the file if it doesn't already exist.
170      */
171     public static final int MODE_CREATE = 0x08000000;
172 
173     /**
174      * For use with {@link #open}: erase contents of file when opening.
175      */
176     public static final int MODE_TRUNCATE = 0x04000000;
177 
178     /**
179      * For use with {@link #open}: append to end of file while writing.
180      */
181     public static final int MODE_APPEND = 0x02000000;
182 
183     /**
184      * Create a new ParcelFileDescriptor wrapped around another descriptor. By
185      * default all method calls are delegated to the wrapped descriptor.
186      */
ParcelFileDescriptor(ParcelFileDescriptor wrapped)187     public ParcelFileDescriptor(ParcelFileDescriptor wrapped) {
188         // We keep a strong reference to the wrapped PFD, and rely on its
189         // finalizer to trigger CloseGuard. All calls are delegated to wrapper.
190         mWrapped = wrapped;
191         mFd = null;
192         mCommFd = null;
193         mClosed = true;
194     }
195 
196     /** {@hide} */
197     @UnsupportedAppUsage
ParcelFileDescriptor(FileDescriptor fd)198     public ParcelFileDescriptor(FileDescriptor fd) {
199         this(fd, null);
200     }
201 
202     /** {@hide} */
ParcelFileDescriptor(FileDescriptor fd, FileDescriptor commChannel)203     public ParcelFileDescriptor(FileDescriptor fd, FileDescriptor commChannel) {
204         if (fd == null) {
205             throw new NullPointerException("FileDescriptor must not be null");
206         }
207         mWrapped = null;
208         mFd = fd;
209         setFdOwner(mFd);
210 
211         mCommFd = commChannel;
212         if (mCommFd != null) {
213             setFdOwner(mCommFd);
214         }
215 
216         mGuard.open("close");
217     }
218 
219     /**
220      * Create a new ParcelFileDescriptor accessing a given file.
221      * <p>
222      * This method should only be used for files that you have direct access to;
223      * if you'd like to work with files hosted outside your app, use an API like
224      * {@link ContentResolver#openFile(Uri, String, CancellationSignal)}.
225      *
226      * @param file The file to be opened.
227      * @param mode The desired access mode, must be one of
228      *            {@link #MODE_READ_ONLY}, {@link #MODE_WRITE_ONLY}, or
229      *            {@link #MODE_READ_WRITE}; may also be any combination of
230      *            {@link #MODE_CREATE}, {@link #MODE_TRUNCATE},
231      *            {@link #MODE_WORLD_READABLE}, and
232      *            {@link #MODE_WORLD_WRITEABLE}.
233      * @return a new ParcelFileDescriptor pointing to the given file.
234      * @throws FileNotFoundException if the given file does not exist or can not
235      *             be opened with the requested mode.
236      * @see #parseMode(String)
237      */
open(File file, int mode)238     public static ParcelFileDescriptor open(File file, int mode) throws FileNotFoundException {
239         final FileDescriptor fd = openInternal(file, mode);
240         if (fd == null) return null;
241 
242         return new ParcelFileDescriptor(fd);
243     }
244 
245     /**
246      * Create a new ParcelFileDescriptor accessing a given file.
247      * <p>
248      * This method should only be used for files that you have direct access to;
249      * if you'd like to work with files hosted outside your app, use an API like
250      * {@link ContentResolver#openFile(Uri, String, CancellationSignal)}.
251      *
252      * @param file The file to be opened.
253      * @param mode The desired access mode, must be one of
254      *            {@link #MODE_READ_ONLY}, {@link #MODE_WRITE_ONLY}, or
255      *            {@link #MODE_READ_WRITE}; may also be any combination of
256      *            {@link #MODE_CREATE}, {@link #MODE_TRUNCATE},
257      *            {@link #MODE_WORLD_READABLE}, and
258      *            {@link #MODE_WORLD_WRITEABLE}.
259      * @param handler to call listener from; must not be null.
260      * @param listener to be invoked when the returned descriptor has been
261      *            closed; must not be null.
262      * @return a new ParcelFileDescriptor pointing to the given file.
263      * @throws FileNotFoundException if the given file does not exist or can not
264      *             be opened with the requested mode.
265      * @see #parseMode(String)
266      */
267     // We can't accept a generic Executor here, since we need to use
268     // MessageQueue.addOnFileDescriptorEventListener()
269     @SuppressLint("ExecutorRegistration")
open(File file, int mode, Handler handler, final OnCloseListener listener)270     public static ParcelFileDescriptor open(File file, int mode, Handler handler,
271             final OnCloseListener listener) throws IOException {
272         if (handler == null) {
273             throw new IllegalArgumentException("Handler must not be null");
274         }
275         if (listener == null) {
276             throw new IllegalArgumentException("Listener must not be null");
277         }
278 
279         final FileDescriptor fd = openInternal(file, mode);
280         if (fd == null) return null;
281 
282         return fromFd(fd, handler, listener);
283     }
284 
285     /**
286      * Create a new ParcelFileDescriptor wrapping an already-opened file.
287      *
288      * @param pfd The already-opened file.
289      * @param handler to call listener from.
290      * @param listener to be invoked when the returned descriptor has been
291      *            closed.
292      * @return a new ParcelFileDescriptor pointing to the given file.
293      */
294     // We can't accept a generic Executor here, since we need to use
295     // MessageQueue.addOnFileDescriptorEventListener()
296     @RavenwoodThrow(blockedBy = MessageQueue.class)
297     @SuppressLint("ExecutorRegistration")
wrap(@onNull ParcelFileDescriptor pfd, @NonNull Handler handler, @NonNull OnCloseListener listener)298     public static @NonNull ParcelFileDescriptor wrap(@NonNull ParcelFileDescriptor pfd,
299             @NonNull Handler handler, @NonNull OnCloseListener listener) throws IOException {
300         final FileDescriptor original = new FileDescriptor();
301         setFdInt(original, pfd.detachFd());
302         return fromFd(original, handler, listener);
303     }
304 
305     /** {@hide} */
306     @RavenwoodThrow(blockedBy = MessageQueue.class)
fromFd(FileDescriptor fd, Handler handler, final OnCloseListener listener)307     public static ParcelFileDescriptor fromFd(FileDescriptor fd, Handler handler,
308             final OnCloseListener listener) throws IOException {
309         if (handler == null) {
310             throw new IllegalArgumentException("Handler must not be null");
311         }
312         if (listener == null) {
313             throw new IllegalArgumentException("Listener must not be null");
314         }
315 
316         final FileDescriptor[] comm = createCommSocketPair();
317         final ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd, comm[0]);
318         final MessageQueue queue = handler.getLooper().getQueue();
319         queue.addOnFileDescriptorEventListener(comm[1],
320                 OnFileDescriptorEventListener.EVENT_INPUT, new OnFileDescriptorEventListener() {
321             @Override
322             public int onFileDescriptorEvents(FileDescriptor fd, int events) {
323                 Status status = null;
324                 if ((events & OnFileDescriptorEventListener.EVENT_INPUT) != 0) {
325                     final byte[] buf = new byte[MAX_STATUS];
326                     status = readCommStatus(fd, buf);
327                 } else if ((events & OnFileDescriptorEventListener.EVENT_ERROR) != 0) {
328                     status = new Status(Status.DEAD);
329                 }
330                 if (status != null) {
331                     queue.removeOnFileDescriptorEventListener(fd);
332                     closeInternal(fd);
333                     listener.onClose(status.asIOException());
334                     return 0;
335                 }
336                 return EVENT_INPUT;
337             }
338         });
339 
340         return pfd;
341     }
342 
343     @RavenwoodReplace
openInternal(File file, int mode)344     private static FileDescriptor openInternal(File file, int mode) throws FileNotFoundException {
345         if ((mode & MODE_WRITE_ONLY) != 0 && (mode & MODE_APPEND) == 0
346                 && (mode & MODE_TRUNCATE) == 0 && ((mode & MODE_READ_ONLY) == 0)
347                 && file != null && file.exists()) {
348             Slog.wtfQuiet(TAG, "ParcelFileDescriptor.open is called with w without t or a or r, "
349                     + "which will have a different behavior beginning in Android Q."
350                     + "\nMode: " + mode + "\nFilename: " + file.getPath());
351         }
352 
353         final int flags = FileUtils.translateModePfdToPosix(mode) | ifAtLeastQ(O_CLOEXEC);
354 
355         int realMode = S_IRWXU | S_IRWXG;
356         if ((mode & MODE_WORLD_READABLE) != 0) realMode |= S_IROTH;
357         if ((mode & MODE_WORLD_WRITEABLE) != 0) realMode |= S_IWOTH;
358 
359         final String path = file.getPath();
360         try {
361             return Os.open(path, flags, realMode);
362         } catch (ErrnoException e) {
363             throw new FileNotFoundException(e.getMessage());
364         }
365     }
366 
openInternal$ravenwood(File file, int mode)367     private static FileDescriptor openInternal$ravenwood(File file, int mode)
368             throws FileNotFoundException {
369         try {
370             return native_open$ravenwood(file, mode);
371         } catch (FileNotFoundException e) {
372             throw e;
373         } catch (IOException e) {
374             throw new FileNotFoundException(e.getMessage());
375         }
376     }
377 
378     @RavenwoodReplace
closeInternal(FileDescriptor fd)379     private static void closeInternal(FileDescriptor fd) {
380         IoUtils.closeQuietly(fd);
381     }
382 
closeInternal$ravenwood(FileDescriptor fd)383     private static void closeInternal$ravenwood(FileDescriptor fd) {
384         native_close$ravenwood(fd);
385     }
386 
387     /**
388      * Create a new ParcelFileDescriptor that is a dup of an existing
389      * FileDescriptor.  This obeys standard POSIX semantics, where the
390      * new file descriptor shared state such as file position with the
391      * original file descriptor.
392      */
dup(FileDescriptor orig)393     public static ParcelFileDescriptor dup(FileDescriptor orig) throws IOException {
394         try {
395             final FileDescriptor fd = new FileDescriptor();
396             int intfd = Os.fcntlInt(orig, (isAtLeastQ() ? F_DUPFD_CLOEXEC : F_DUPFD), 0);
397             setFdInt(fd, intfd);
398             return new ParcelFileDescriptor(fd);
399         } catch (ErrnoException e) {
400             throw e.rethrowAsIOException();
401         }
402     }
403 
404     /**
405      * Create a new ParcelFileDescriptor that is a dup of the existing
406      * FileDescriptor.  This obeys standard POSIX semantics, where the
407      * new file descriptor shared state such as file position with the
408      * original file descriptor.
409      */
dup()410     public ParcelFileDescriptor dup() throws IOException {
411         if (mWrapped != null) {
412             return mWrapped.dup();
413         } else {
414             return dup(getFileDescriptor());
415         }
416     }
417 
418     /**
419      * Create a new ParcelFileDescriptor from a raw native fd.  The new
420      * ParcelFileDescriptor holds a dup of the original fd passed in here,
421      * so you must still close that fd as well as the new ParcelFileDescriptor.
422      *
423      * @param fd The native fd that the ParcelFileDescriptor should dup.
424      *
425      * @return Returns a new ParcelFileDescriptor holding a FileDescriptor
426      * for a dup of the given fd.
427      */
fromFd(int fd)428     public static ParcelFileDescriptor fromFd(int fd) throws IOException {
429         final FileDescriptor original = new FileDescriptor();
430         setFdInt(original, fd);
431 
432         try {
433             final FileDescriptor dup = new FileDescriptor();
434             int intfd = Os.fcntlInt(original, (isAtLeastQ() ? F_DUPFD_CLOEXEC : F_DUPFD), 0);
435             setFdInt(dup, intfd);
436             return new ParcelFileDescriptor(dup);
437         } catch (ErrnoException e) {
438             throw e.rethrowAsIOException();
439         }
440     }
441 
442     /**
443      * Take ownership of a raw native fd in to a new ParcelFileDescriptor.
444      * The returned ParcelFileDescriptor now owns the given fd, and will be
445      * responsible for closing it.
446      * <p>
447      * <strong>WARNING:</strong> You must not close the fd yourself after
448      * this call, and ownership of the file descriptor must have been
449      * released prior to the call to this function.
450      *
451      * @param fd The native fd that the ParcelFileDescriptor should adopt.
452      *
453      * @return Returns a new ParcelFileDescriptor holding a FileDescriptor
454      * for the given fd.
455      */
adoptFd(int fd)456     public static ParcelFileDescriptor adoptFd(int fd) {
457         final FileDescriptor fdesc = new FileDescriptor();
458         setFdInt(fdesc, fd);
459 
460         return new ParcelFileDescriptor(fdesc);
461     }
462 
463     /**
464      * Create a new ParcelFileDescriptor from the specified Socket.  The new
465      * ParcelFileDescriptor holds a dup of the original FileDescriptor in
466      * the Socket, so you must still close the Socket as well as the new
467      * ParcelFileDescriptor.
468      * <p>
469      * <strong>WARNING:</strong> Prior to API level 29, this function would not
470      * actually dup the Socket's FileDescriptor, and would take a
471      * reference to the its internal FileDescriptor instead. If the Socket
472      * gets garbage collected before the ParcelFileDescriptor, this may
473      * lead to the ParcelFileDescriptor being unexpectedly closed. To avoid
474      * this, the following pattern can be used:
475      * <pre>{@code
476      *    ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket).dup();
477      * }</pre>
478      *
479      * @param socket The Socket whose FileDescriptor is used to create
480      *               a new ParcelFileDescriptor.
481      *
482      * @return A new ParcelFileDescriptor with a duped copy of the
483      * FileDescriptor of the specified Socket.
484      *
485      * @throws UncheckedIOException if {@link #dup(FileDescriptor)} throws IOException.
486      */
487     @RavenwoodThrow(reason = "Socket.getFileDescriptor$()")
fromSocket(Socket socket)488     public static ParcelFileDescriptor fromSocket(Socket socket) {
489         FileDescriptor fd = socket.getFileDescriptor$();
490         try {
491             return fd != null ? ParcelFileDescriptor.dup(fd) : null;
492         } catch (IOException e) {
493             throw new UncheckedIOException(e);
494         }
495     }
496 
497     /**
498      * Create a new ParcelFileDescriptor from the specified DatagramSocket. The
499      * new ParcelFileDescriptor holds a dup of the original FileDescriptor in
500      * the DatagramSocket, so you must still close the DatagramSocket as well
501      * as the new ParcelFileDescriptor.
502      * <p>
503      * <strong>WARNING:</strong> Prior to API level 29, this function would not
504      * actually dup the DatagramSocket's FileDescriptor, and would take a
505      * reference to the its internal FileDescriptor instead. If the DatagramSocket
506      * gets garbage collected before the ParcelFileDescriptor, this may
507      * lead to the ParcelFileDescriptor being unexpectedly closed. To avoid
508      * this, the following pattern can be used:
509      * <pre>{@code
510      *    ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(socket).dup();
511      * }</pre>
512      *
513      * @param datagramSocket The DatagramSocket whose FileDescriptor is used
514      *               to create a new ParcelFileDescriptor.
515      *
516      * @return A new ParcelFileDescriptor with a duped copy of the
517      * FileDescriptor of the specified Socket.
518      *
519      * @throws UncheckedIOException if {@link #dup(FileDescriptor)} throws IOException.
520      */
521     @RavenwoodThrow(reason = "DatagramSocket.getFileDescriptor$()")
fromDatagramSocket(DatagramSocket datagramSocket)522     public static ParcelFileDescriptor fromDatagramSocket(DatagramSocket datagramSocket) {
523         FileDescriptor fd = datagramSocket.getFileDescriptor$();
524         try {
525             return fd != null ? ParcelFileDescriptor.dup(fd) : null;
526         } catch (IOException e) {
527             throw new UncheckedIOException(e);
528         }
529     }
530 
531     /**
532      * Create two ParcelFileDescriptors structured as a data pipe.  The first
533      * ParcelFileDescriptor in the returned array is the read side; the second
534      * is the write side.
535      */
createPipe()536     public static ParcelFileDescriptor[] createPipe() throws IOException {
537         try {
538             final FileDescriptor[] fds = Os.pipe2(ifAtLeastQ(O_CLOEXEC));
539             return new ParcelFileDescriptor[] {
540                     new ParcelFileDescriptor(fds[0]),
541                     new ParcelFileDescriptor(fds[1]) };
542         } catch (ErrnoException e) {
543             throw e.rethrowAsIOException();
544         }
545     }
546 
547     /**
548      * Create two ParcelFileDescriptors structured as a data pipe. The first
549      * ParcelFileDescriptor in the returned array is the read side; the second
550      * is the write side.
551      * <p>
552      * The write end has the ability to deliver an error message through
553      * {@link #closeWithError(String)} which can be handled by the read end
554      * calling {@link #checkError()}, usually after detecting an EOF.
555      * This can also be used to detect remote crashes.
556      */
createReliablePipe()557     public static ParcelFileDescriptor[] createReliablePipe() throws IOException {
558         try {
559             final FileDescriptor[] comm = createCommSocketPair();
560             final FileDescriptor[] fds = Os.pipe2(ifAtLeastQ(O_CLOEXEC));
561             return new ParcelFileDescriptor[] {
562                     new ParcelFileDescriptor(fds[0], comm[0]),
563                     new ParcelFileDescriptor(fds[1], comm[1]) };
564         } catch (ErrnoException e) {
565             throw e.rethrowAsIOException();
566         }
567     }
568 
569     /**
570      * Create two ParcelFileDescriptors structured as a pair of sockets
571      * connected to each other. The two sockets are indistinguishable.
572      */
573     @RavenwoodThrow(reason = "Os.socketpair()")
createSocketPair()574     public static ParcelFileDescriptor[] createSocketPair() throws IOException {
575         return createSocketPair(SOCK_STREAM);
576     }
577 
578     /**
579      * @hide
580      */
581     @RavenwoodThrow(reason = "Os.socketpair()")
createSocketPair(int type)582     public static ParcelFileDescriptor[] createSocketPair(int type) throws IOException {
583         try {
584             final FileDescriptor fd0 = new FileDescriptor();
585             final FileDescriptor fd1 = new FileDescriptor();
586             Os.socketpair(AF_UNIX, type | ifAtLeastQ(SOCK_CLOEXEC), 0, fd0, fd1);
587             return new ParcelFileDescriptor[] {
588                     new ParcelFileDescriptor(fd0),
589                     new ParcelFileDescriptor(fd1) };
590         } catch (ErrnoException e) {
591             throw e.rethrowAsIOException();
592         }
593     }
594 
595     /**
596      * Create two ParcelFileDescriptors structured as a pair of sockets
597      * connected to each other. The two sockets are indistinguishable.
598      * <p>
599      * Both ends have the ability to deliver an error message through
600      * {@link #closeWithError(String)} which can be detected by the other end
601      * calling {@link #checkError()}, usually after detecting an EOF.
602      * This can also be used to detect remote crashes.
603      */
604     @RavenwoodThrow(reason = "Os.socketpair()")
createReliableSocketPair()605     public static ParcelFileDescriptor[] createReliableSocketPair() throws IOException {
606         return createReliableSocketPair(SOCK_STREAM);
607     }
608 
609     /**
610      * @hide
611      */
612     @RavenwoodThrow(reason = "Os.socketpair()")
createReliableSocketPair(int type)613     public static ParcelFileDescriptor[] createReliableSocketPair(int type) throws IOException {
614         try {
615             final FileDescriptor[] comm = createCommSocketPair();
616             final FileDescriptor fd0 = new FileDescriptor();
617             final FileDescriptor fd1 = new FileDescriptor();
618             Os.socketpair(AF_UNIX, type | ifAtLeastQ(SOCK_CLOEXEC), 0, fd0, fd1);
619             return new ParcelFileDescriptor[] {
620                     new ParcelFileDescriptor(fd0, comm[0]),
621                     new ParcelFileDescriptor(fd1, comm[1]) };
622         } catch (ErrnoException e) {
623             throw e.rethrowAsIOException();
624         }
625     }
626 
627     @RavenwoodThrow(reason = "Os.socketpair()")
createCommSocketPair()628     private static FileDescriptor[] createCommSocketPair() throws IOException {
629         try {
630             // Use SOCK_SEQPACKET so that we have a guarantee that the status
631             // is written and read atomically as one unit and is not split
632             // across multiple IO operations.
633             final FileDescriptor comm1 = new FileDescriptor();
634             final FileDescriptor comm2 = new FileDescriptor();
635             Os.socketpair(AF_UNIX, SOCK_SEQPACKET | ifAtLeastQ(SOCK_CLOEXEC), 0, comm1, comm2);
636             IoUtils.setBlocking(comm1, false);
637             IoUtils.setBlocking(comm2, false);
638             return new FileDescriptor[] { comm1, comm2 };
639         } catch (ErrnoException e) {
640             throw e.rethrowAsIOException();
641         }
642     }
643 
644     /**
645      * @hide Please use createPipe() or ContentProvider.openPipeHelper().
646      * Gets a file descriptor for a read-only copy of the given data.
647      *
648      * @param data Data to copy.
649      * @param name Name for the shared memory area that may back the file descriptor.
650      *        This is purely informative and may be {@code null}.
651      * @return A ParcelFileDescriptor.
652      * @throws IOException if there is an error while creating the shared memory area.
653      */
654     @UnsupportedAppUsage
655     @Deprecated
656     @RavenwoodThrow(blockedBy = MemoryFile.class)
fromData(byte[] data, String name)657     public static ParcelFileDescriptor fromData(byte[] data, String name) throws IOException {
658         if (data == null) return null;
659         MemoryFile file = new MemoryFile(name, data.length);
660         try {
661             if (data.length > 0) {
662                 file.writeBytes(data, 0, 0, data.length);
663             }
664             file.deactivate();
665             FileDescriptor fd = file.getFileDescriptor();
666             return fd != null ? ParcelFileDescriptor.dup(fd) : null;
667         } finally {
668             file.close();
669         }
670     }
671 
672     /**
673      * Converts a string representing a file mode, such as "rw", into a bitmask suitable for use
674      * with {@link #open}.
675      * <p>
676      * The argument must define at least one of the following base access modes:
677      * <ul>
678      * <li>"r" indicates the file should be opened in read-only mode, equivalent
679      * to {@link OsConstants#O_RDONLY}.
680      * <li>"w" indicates the file should be opened in write-only mode,
681      * equivalent to {@link OsConstants#O_WRONLY}.
682      * <li>"rw" indicates the file should be opened in read-write mode,
683      * equivalent to {@link OsConstants#O_RDWR}.
684      * </ul>
685      * In addition to a base access mode, the following additional modes may
686      * requested:
687      * <ul>
688      * <li>"a" indicates the file should be opened in append mode, equivalent to
689      * {@link OsConstants#O_APPEND}. Before each write, the file offset is
690      * positioned at the end of the file.
691      * <li>"t" indicates the file should be opened in truncate mode, equivalent
692      * to {@link OsConstants#O_TRUNC}. If the file already exists and is a
693      * regular file and is opened for writing, it will be truncated to length 0.
694      * </ul>
695      *
696      * @param mode The string representation of the file mode. Can be "r", "w", "wt", "wa", "rw"
697      *             or "rwt".
698      * @return A bitmask representing the given file mode.
699      * @throws IllegalArgumentException if the given string does not match a known file mode.
700      */
parseMode(String mode)701     public static int parseMode(String mode) {
702         return FileUtils.translateModePosixToPfd(FileUtils.translateModeStringToPosix(mode));
703     }
704 
705     /**
706      * Return the filesystem path of the real file on disk that is represented
707      * by the given {@link FileDescriptor}.
708      *
709      * @hide
710      */
711     @TestApi
712     @RavenwoodThrow(reason = "Os.readlink() and Os.stat()")
getFile(FileDescriptor fd)713     public static File getFile(FileDescriptor fd) throws IOException {
714         try {
715             final String path = Os.readlink("/proc/self/fd/" + getFdInt(fd));
716             if (OsConstants.S_ISREG(Os.stat(path).st_mode)
717                     || OsConstants.S_ISCHR(Os.stat(path).st_mode)) {
718                 return new File(path);
719             } else {
720                 throw new IOException("Not a regular file or character device: " + path);
721             }
722         } catch (ErrnoException e) {
723             throw e.rethrowAsIOException();
724         }
725     }
726 
727     /**
728      * Retrieve the actual FileDescriptor associated with this object.
729      *
730      * @return Returns the FileDescriptor associated with this object.
731      */
getFileDescriptor()732     public FileDescriptor getFileDescriptor() {
733         if (mWrapped != null) {
734             return mWrapped.getFileDescriptor();
735         } else {
736             return mFd;
737         }
738     }
739 
740     /**
741      * Return the total size of the file representing this fd, as determined by
742      * {@code stat()}. Returns -1 if the fd is not a file.
743      */
744     @RavenwoodThrow(reason = "Os.readlink() and Os.stat()")
getStatSize()745     public long getStatSize() {
746         if (mWrapped != null) {
747             return mWrapped.getStatSize();
748         } else {
749             try {
750                 final StructStat st = Os.fstat(mFd);
751                 if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
752                     return st.st_size;
753                 } else {
754                     return -1;
755                 }
756             } catch (ErrnoException e) {
757                 Log.w(TAG, "fstat() failed: " + e);
758                 return -1;
759             }
760         }
761     }
762 
763     /**
764      * This is needed for implementing AssetFileDescriptor.AutoCloseOutputStream,
765      * and I really don't think we want it to be public.
766      * @hide
767      */
768     @UnsupportedAppUsage
seekTo(long pos)769     public long seekTo(long pos) throws IOException {
770         if (mWrapped != null) {
771             return mWrapped.seekTo(pos);
772         } else {
773             try {
774                 return Os.lseek(mFd, pos, SEEK_SET);
775             } catch (ErrnoException e) {
776                 throw e.rethrowAsIOException();
777             }
778         }
779     }
780 
781     /**
782      * Return the native fd int for this ParcelFileDescriptor.  The
783      * ParcelFileDescriptor still owns the fd, and it still must be closed
784      * through this API.
785      * <p>
786      * <strong>WARNING:</strong> Do not call close on the return value of this
787      * function or pass it to a function that assumes ownership of the fd.
788      */
getFd()789     public int getFd() {
790         if (mWrapped != null) {
791             return mWrapped.getFd();
792         } else {
793             if (mClosed) {
794                 throw new IllegalStateException("Already closed");
795             }
796             return getFdInt(mFd);
797         }
798     }
799 
800     /**
801      * Return the native fd int for this ParcelFileDescriptor and detach it from
802      * the object here. You are now responsible for closing the fd in native
803      * code.
804      * <p>
805      * You should not detach when the original creator of the descriptor is
806      * expecting a reliable signal through {@link #close()} or
807      * {@link #closeWithError(String)}.
808      *
809      * @see #canDetectErrors()
810      */
detachFd()811     public int detachFd() {
812         if (mWrapped != null) {
813             return mWrapped.detachFd();
814         } else {
815             if (mClosed) {
816                 throw new IllegalStateException("Already closed");
817             }
818             int fd = acquireRawFd(mFd);
819             writeCommStatusAndClose(Status.DETACHED, null);
820             mClosed = true;
821             mGuard.close();
822             releaseResources();
823             return fd;
824         }
825     }
826 
827     /**
828      * Close the ParcelFileDescriptor. This implementation closes the underlying
829      * OS resources allocated to represent this stream.
830      *
831      * @throws IOException
832      *             If an error occurs attempting to close this ParcelFileDescriptor.
833      */
834     @Override
close()835     public void close() throws IOException {
836         if (mWrapped != null) {
837             try {
838                 mWrapped.close();
839             } finally {
840                 releaseResources();
841             }
842         } else {
843             closeWithStatus(Status.OK, null);
844         }
845     }
846 
847     /**
848      * Close the ParcelFileDescriptor, informing any peer that an error occurred
849      * while processing. If the creator of this descriptor is not observing
850      * errors, it will close normally.
851      *
852      * @param msg describing the error; must not be null.
853      */
closeWithError(String msg)854     public void closeWithError(String msg) throws IOException {
855         if (mWrapped != null) {
856             try {
857                 mWrapped.closeWithError(msg);
858             } finally {
859                 releaseResources();
860             }
861         } else {
862             if (msg == null) {
863                 throw new IllegalArgumentException("Message must not be null");
864             }
865             closeWithStatus(Status.ERROR, msg);
866         }
867     }
868 
closeWithStatus(int status, String msg)869     private void closeWithStatus(int status, String msg) {
870         if (mClosed) return;
871         mClosed = true;
872         if (mGuard != null) {
873             mGuard.close();
874         }
875         // Status MUST be sent before closing actual descriptor
876         writeCommStatusAndClose(status, msg);
877         closeInternal(mFd);
878         releaseResources();
879     }
880 
881     /**
882      * Called when the fd is being closed, for subclasses to release any other resources
883      * associated with it, such as acquired providers.
884      * @hide
885      */
releaseResources()886     public void releaseResources() {
887     }
888 
getOrCreateStatusBuffer()889     private byte[] getOrCreateStatusBuffer() {
890         if (mStatusBuf == null) {
891             mStatusBuf = new byte[MAX_STATUS];
892         }
893         return mStatusBuf;
894     }
895 
writeCommStatusAndClose(int status, String msg)896     private void writeCommStatusAndClose(int status, String msg) {
897         if (mCommFd == null) {
898             // Not reliable, or someone already sent status
899             if (msg != null) {
900                 Log.w(TAG, "Unable to inform peer: " + msg);
901             }
902             return;
903         }
904 
905         if (status == Status.DETACHED) {
906             Log.w(TAG, "Peer expected signal when closed; unable to deliver after detach");
907         }
908 
909         try {
910             if (status == Status.SILENCE) return;
911 
912             // Since we're about to close, read off any remote status. It's
913             // okay to remember missing here.
914             mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer());
915 
916             // Skip writing status when other end has already gone away.
917             if (mStatus != null) return;
918 
919             try {
920                 final byte[] buf = getOrCreateStatusBuffer();
921                 int writePtr = 0;
922 
923                 Memory.pokeInt(buf, writePtr, status, ByteOrder.BIG_ENDIAN);
924                 writePtr += 4;
925 
926                 if (msg != null) {
927                     final byte[] rawMsg = msg.getBytes();
928                     final int len = Math.min(rawMsg.length, buf.length - writePtr);
929                     System.arraycopy(rawMsg, 0, buf, writePtr, len);
930                     writePtr += len;
931                 }
932 
933                 // Must write the entire status as a single operation.
934                 Os.write(mCommFd, buf, 0, writePtr);
935             } catch (ErrnoException e) {
936                 // Reporting status is best-effort
937                 Log.w(TAG, "Failed to report status: " + e);
938             } catch (InterruptedIOException e) {
939                 // Reporting status is best-effort
940                 Log.w(TAG, "Failed to report status: " + e);
941             }
942 
943         } finally {
944             closeInternal(mCommFd);
945             mCommFd = null;
946         }
947     }
948 
readCommStatus(FileDescriptor comm, byte[] buf)949     private static Status readCommStatus(FileDescriptor comm, byte[] buf) {
950         try {
951             // Must read the entire status as a single operation.
952             final int n = Os.read(comm, buf, 0, buf.length);
953             if (n == 0) {
954                 // EOF means they're dead
955                 return new Status(Status.DEAD);
956             } else {
957                 final int status = Memory.peekInt(buf, 0, ByteOrder.BIG_ENDIAN);
958                 if (status == Status.ERROR) {
959                     final String msg = new String(buf, 4, n - 4);
960                     return new Status(status, msg);
961                 }
962                 return new Status(status);
963             }
964         } catch (ErrnoException e) {
965             if (e.errno == OsConstants.EAGAIN) {
966                 // Remote is still alive, but no status written yet
967                 return null;
968             } else {
969                 Log.d(TAG, "Failed to read status; assuming dead: " + e);
970                 return new Status(Status.DEAD);
971             }
972         } catch (InterruptedIOException e) {
973             Log.d(TAG, "Failed to read status; assuming dead: " + e);
974             return new Status(Status.DEAD);
975         }
976     }
977 
978     /**
979      * Indicates if this ParcelFileDescriptor can communicate and detect remote
980      * errors/crashes.
981      *
982      * @see #checkError()
983      */
canDetectErrors()984     public boolean canDetectErrors() {
985         if (mWrapped != null) {
986             return mWrapped.canDetectErrors();
987         } else {
988             return mCommFd != null;
989         }
990     }
991 
992     /**
993      * Detect and throw if the other end of a pipe or socket pair encountered an
994      * error or crashed. This allows a reader to distinguish between a valid EOF
995      * and an error/crash.
996      * <p>
997      * If this ParcelFileDescriptor is unable to detect remote errors, it will
998      * return silently.
999      *
1000      * @throws IOException for normal errors.
1001      * @throws FileDescriptorDetachedException
1002      *            if the remote side called {@link #detachFd()}. Once detached, the remote
1003      *            side is unable to communicate any errors through
1004      *            {@link #closeWithError(String)}.
1005      * @see #canDetectErrors()
1006      */
checkError()1007     public void checkError() throws IOException {
1008         if (mWrapped != null) {
1009             mWrapped.checkError();
1010         } else {
1011             if (mStatus == null) {
1012                 if (mCommFd == null) {
1013                     Log.w(TAG, "Peer didn't provide a comm channel; unable to check for errors");
1014                     return;
1015                 }
1016 
1017                 // Try reading status; it might be null if nothing written yet.
1018                 // Either way, we keep comm open to write our status later.
1019                 mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer());
1020             }
1021 
1022             if (mStatus == null || mStatus.status == Status.OK) {
1023                 // No status yet, or everything is peachy!
1024                 return;
1025             } else {
1026                 throw mStatus.asIOException();
1027             }
1028         }
1029     }
1030 
1031     /**
1032      * An InputStream you can create on a ParcelFileDescriptor, which will
1033      * take care of calling {@link ParcelFileDescriptor#close
1034      * ParcelFileDescriptor.close()} for you when the stream is closed.
1035      */
1036     public static class AutoCloseInputStream extends FileInputStream {
1037         private final ParcelFileDescriptor mPfd;
1038 
AutoCloseInputStream(ParcelFileDescriptor pfd)1039         public AutoCloseInputStream(ParcelFileDescriptor pfd) {
1040             super(pfd.getFileDescriptor());
1041             mPfd = pfd;
1042         }
1043 
1044         @Override
close()1045         public void close() throws IOException {
1046             try {
1047                 super.close();
1048             } finally {
1049                 mPfd.close();
1050             }
1051         }
1052 
1053         @Override
read()1054         public int read() throws IOException {
1055             final int result = super.read();
1056             if (result == -1 && mPfd.canDetectErrors()) {
1057                 // Check for errors only on EOF, to minimize overhead.
1058                 mPfd.checkError();
1059             }
1060             return result;
1061         }
1062 
1063         @Override
read(byte[] b)1064         public int read(byte[] b) throws IOException {
1065             final int result = super.read(b);
1066             if (result == -1 && mPfd.canDetectErrors()) {
1067                 mPfd.checkError();
1068             }
1069             return result;
1070         }
1071 
1072         @Override
read(byte[] b, int off, int len)1073         public int read(byte[] b, int off, int len) throws IOException {
1074             final int result = super.read(b, off, len);
1075             if (result == -1 && mPfd.canDetectErrors()) {
1076                 mPfd.checkError();
1077             }
1078             return result;
1079         }
1080     }
1081 
1082     /**
1083      * An OutputStream you can create on a ParcelFileDescriptor, which will
1084      * take care of calling {@link ParcelFileDescriptor#close
1085      * ParcelFileDescriptor.close()} for you when the stream is closed.
1086      */
1087     @RavenwoodKeepWholeClass
1088     public static class AutoCloseOutputStream extends FileOutputStream {
1089         private final ParcelFileDescriptor mPfd;
1090 
AutoCloseOutputStream(ParcelFileDescriptor pfd)1091         public AutoCloseOutputStream(ParcelFileDescriptor pfd) {
1092             super(pfd.getFileDescriptor());
1093             mPfd = pfd;
1094         }
1095 
1096         @Override
close()1097         public void close() throws IOException {
1098             try {
1099                 super.close();
1100             } finally {
1101                 mPfd.close();
1102             }
1103         }
1104     }
1105 
1106     @Override
toString()1107     public String toString() {
1108         if (mWrapped != null) {
1109             return mWrapped.toString();
1110         } else {
1111             return "{ParcelFileDescriptor: " + mFd + "}";
1112         }
1113     }
1114 
1115     @Override
finalize()1116     protected void finalize() throws Throwable {
1117         if (mWrapped != null) {
1118             releaseResources();
1119         }
1120         if (mGuard != null) {
1121             mGuard.warnIfOpen();
1122         }
1123         try {
1124             if (!mClosed) {
1125                 // mWrapped was and is null.
1126                 closeWithStatus(Status.LEAKED, null);
1127             }
1128         } finally {
1129             super.finalize();
1130         }
1131     }
1132 
1133     @Override
describeContents()1134     public int describeContents() {
1135         if (mWrapped != null) {
1136             return mWrapped.describeContents();
1137         } else {
1138             return Parcelable.CONTENTS_FILE_DESCRIPTOR;
1139         }
1140     }
1141 
1142     /**
1143      * {@inheritDoc}
1144      * If {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set in flags,
1145      * the file descriptor will be closed after a copy is written to the Parcel.
1146      */
1147     @Override
writeToParcel(Parcel out, int flags)1148     public void writeToParcel(Parcel out, int flags) {
1149         if (mWrapped != null) {
1150             try {
1151                 mWrapped.writeToParcel(out, flags);
1152             } finally {
1153                 releaseResources();
1154             }
1155         } else {
1156             if (mCommFd != null) {
1157                 out.writeInt(1);
1158                 out.writeFileDescriptor(mFd);
1159                 out.writeFileDescriptor(mCommFd);
1160             } else {
1161                 out.writeInt(0);
1162                 out.writeFileDescriptor(mFd);
1163             }
1164             if ((flags & PARCELABLE_WRITE_RETURN_VALUE) != 0 && !mClosed) {
1165                 // Not a real close, so emit no status
1166                 closeWithStatus(Status.SILENCE, null);
1167             }
1168         }
1169     }
1170 
1171     public static final @android.annotation.NonNull Parcelable.Creator<ParcelFileDescriptor> CREATOR
1172             = new Parcelable.Creator<ParcelFileDescriptor>() {
1173         @Override
1174         public ParcelFileDescriptor createFromParcel(Parcel in) {
1175             int hasCommChannel = in.readInt();
1176             final FileDescriptor fd = in.readRawFileDescriptor();
1177             FileDescriptor commChannel = null;
1178             if (hasCommChannel != 0) {
1179                 commChannel = in.readRawFileDescriptor();
1180             }
1181             return new ParcelFileDescriptor(fd, commChannel);
1182         }
1183 
1184         @Override
1185         public ParcelFileDescriptor[] newArray(int size) {
1186             return new ParcelFileDescriptor[size];
1187         }
1188     };
1189 
1190     /**
1191      * Callback indicating that a ParcelFileDescriptor has been closed.
1192      */
1193     public interface OnCloseListener {
1194         /**
1195          * Event indicating the ParcelFileDescriptor to which this listener was
1196          * attached has been closed.
1197          *
1198          * @param e error state, or {@code null} if closed cleanly.
1199          *        If the close event was the result of
1200          *        {@link ParcelFileDescriptor#detachFd()}, this will be a
1201          *        {@link FileDescriptorDetachedException}. After detach the
1202          *        remote side may continue reading/writing to the underlying
1203          *        {@link FileDescriptor}, but they can no longer deliver
1204          *        reliable close/error events.
1205          */
onClose(IOException e)1206         public void onClose(IOException e);
1207     }
1208 
1209     /**
1210      * Exception that indicates that the file descriptor was detached.
1211      */
1212     public static class FileDescriptorDetachedException extends IOException {
1213 
1214         private static final long serialVersionUID = 0xDe7ac4edFdL;
1215 
FileDescriptorDetachedException()1216         public FileDescriptorDetachedException() {
1217             super("Remote side is detached");
1218         }
1219     }
1220 
1221     /**
1222      * Internal class representing a remote status read by
1223      * {@link ParcelFileDescriptor#readCommStatus(FileDescriptor, byte[])}.
1224      *
1225      * Warning: this must be kept in sync with ParcelFileDescriptorStatus at
1226      * frameworks/native/libs/binder/Parcel.cpp
1227      */
1228     private static class Status {
1229         /** Special value indicating remote side died. */
1230         public static final int DEAD = -2;
1231         /** Special value indicating no status should be written. */
1232         public static final int SILENCE = -1;
1233 
1234         /** Remote reported that everything went better than expected. */
1235         public static final int OK = 0;
1236         /** Remote reported error; length and message follow. */
1237         public static final int ERROR = 1;
1238         /** Remote reported {@link #detachFd()} and went rogue. */
1239         public static final int DETACHED = 2;
1240         /** Remote reported their object was finalized. */
1241         public static final int LEAKED = 3;
1242 
1243         public final int status;
1244         public final String msg;
1245 
Status(int status)1246         public Status(int status) {
1247             this(status, null);
1248         }
1249 
Status(int status, String msg)1250         public Status(int status, String msg) {
1251             this.status = status;
1252             this.msg = msg;
1253         }
1254 
asIOException()1255         public IOException asIOException() {
1256             switch (status) {
1257                 case DEAD:
1258                     return new IOException("Remote side is dead");
1259                 case OK:
1260                     return null;
1261                 case ERROR:
1262                     return new IOException("Remote error: " + msg);
1263                 case DETACHED:
1264                     return new FileDescriptorDetachedException();
1265                 case LEAKED:
1266                     return new IOException("Remote side was leaked");
1267                 default:
1268                     return new IOException("Unknown status: " + status);
1269             }
1270         }
1271 
1272         @Override
toString()1273         public String toString() {
1274             return "{" + status + ": " + msg + "}";
1275         }
1276     }
1277 
1278     // These native methods are currently only implemented by Ravenwood, as it's the only
1279     // mechanism we have to jump to our RavenwoodNativeSubstitutionClass
native_setFdInt$ravenwood(FileDescriptor fd, int fdInt)1280     private static native void native_setFdInt$ravenwood(FileDescriptor fd, int fdInt);
native_getFdInt$ravenwood(FileDescriptor fd)1281     private static native int native_getFdInt$ravenwood(FileDescriptor fd);
native_open$ravenwood(File file, int pfdMode)1282     private static native FileDescriptor native_open$ravenwood(File file, int pfdMode)
1283             throws IOException;
native_close$ravenwood(FileDescriptor fd)1284     private static native void native_close$ravenwood(FileDescriptor fd);
1285 
1286     @RavenwoodReplace
setFdInt(FileDescriptor fd, int fdInt)1287     private static void setFdInt(FileDescriptor fd, int fdInt) {
1288         fd.setInt$(fdInt);
1289     }
1290 
setFdInt$ravenwood(FileDescriptor fd, int fdInt)1291     private static void setFdInt$ravenwood(FileDescriptor fd, int fdInt) {
1292         native_setFdInt$ravenwood(fd, fdInt);
1293     }
1294 
1295     @RavenwoodReplace
getFdInt(FileDescriptor fd)1296     private static int getFdInt(FileDescriptor fd) {
1297         return fd.getInt$();
1298     }
1299 
getFdInt$ravenwood(FileDescriptor fd)1300     private static int getFdInt$ravenwood(FileDescriptor fd) {
1301         return native_getFdInt$ravenwood(fd);
1302     }
1303 
1304     @RavenwoodReplace
setFdOwner(FileDescriptor fd)1305     private void setFdOwner(FileDescriptor fd) {
1306         IoUtils.setFdOwner(fd, this);
1307     }
1308 
setFdOwner$ravenwood(FileDescriptor fd)1309     private void setFdOwner$ravenwood(FileDescriptor fd) {
1310         // FD owners currently unsupported under Ravenwood; ignored
1311     }
1312 
1313     @RavenwoodReplace
acquireRawFd(FileDescriptor fd)1314     private int acquireRawFd(FileDescriptor fd) {
1315         return IoUtils.acquireRawFd(fd);
1316     }
1317 
acquireRawFd$ravenwood(FileDescriptor fd)1318     private int acquireRawFd$ravenwood(FileDescriptor fd) {
1319         // FD owners currently unsupported under Ravenwood; return FD directly
1320         return getFdInt(fd);
1321 
1322     }
1323 
1324     @RavenwoodReplace
isAtLeastQ()1325     private static boolean isAtLeastQ() {
1326         return (VMRuntime.getRuntime().getTargetSdkVersion() >= Build.VERSION_CODES.Q);
1327     }
1328 
isAtLeastQ$ravenwood()1329     private static boolean isAtLeastQ$ravenwood() {
1330         return RavenwoodEnvironment.workaround().isTargetSdkAtLeastQ();
1331     }
1332 
ifAtLeastQ(int value)1333     private static int ifAtLeastQ(int value) {
1334         return isAtLeastQ() ? value : 0;
1335     }
1336 }
1337