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