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