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