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         final FileDescriptor[] comm = createCommSocketPair();
237         final ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd, comm[0]);
238         final MessageQueue queue = handler.getLooper().getQueue();
239         queue.addOnFileDescriptorEventListener(comm[1],
240                 OnFileDescriptorEventListener.EVENT_INPUT, new OnFileDescriptorEventListener() {
241             @Override
242             public int onFileDescriptorEvents(FileDescriptor fd, int events) {
243                 Status status = null;
244                 if ((events & OnFileDescriptorEventListener.EVENT_INPUT) != 0) {
245                     final byte[] buf = new byte[MAX_STATUS];
246                     status = readCommStatus(fd, buf);
247                 } else if ((events & OnFileDescriptorEventListener.EVENT_ERROR) != 0) {
248                     status = new Status(Status.DEAD);
249                 }
250                 if (status != null) {
251                     queue.removeOnFileDescriptorEventListener(fd);
252                     IoUtils.closeQuietly(fd);
253                     listener.onClose(status.asIOException());
254                     return 0;
255                 }
256                 return EVENT_INPUT;
257             }
258         });
259 
260         return pfd;
261     }
262 
openInternal(File file, int mode)263     private static FileDescriptor openInternal(File file, int mode) throws FileNotFoundException {
264         if ((mode & MODE_READ_WRITE) == 0) {
265             throw new IllegalArgumentException(
266                     "Must specify MODE_READ_ONLY, MODE_WRITE_ONLY, or MODE_READ_WRITE");
267         }
268 
269         final String path = file.getPath();
270         return Parcel.openFileDescriptor(path, mode);
271     }
272 
273     /**
274      * Create a new ParcelFileDescriptor that is a dup of an existing
275      * FileDescriptor.  This obeys standard POSIX semantics, where the
276      * new file descriptor shared state such as file position with the
277      * original file descriptor.
278      */
dup(FileDescriptor orig)279     public static ParcelFileDescriptor dup(FileDescriptor orig) throws IOException {
280         try {
281             final FileDescriptor fd = Os.dup(orig);
282             return new ParcelFileDescriptor(fd);
283         } catch (ErrnoException e) {
284             throw e.rethrowAsIOException();
285         }
286     }
287 
288     /**
289      * Create a new ParcelFileDescriptor that is a dup of the existing
290      * FileDescriptor.  This obeys standard POSIX semantics, where the
291      * new file descriptor shared state such as file position with the
292      * original file descriptor.
293      */
dup()294     public ParcelFileDescriptor dup() throws IOException {
295         if (mWrapped != null) {
296             return mWrapped.dup();
297         } else {
298             return dup(getFileDescriptor());
299         }
300     }
301 
302     /**
303      * Create a new ParcelFileDescriptor from a raw native fd.  The new
304      * ParcelFileDescriptor holds a dup of the original fd passed in here,
305      * so you must still close that fd as well as the new ParcelFileDescriptor.
306      *
307      * @param fd The native fd that the ParcelFileDescriptor should dup.
308      *
309      * @return Returns a new ParcelFileDescriptor holding a FileDescriptor
310      * for a dup of the given fd.
311      */
fromFd(int fd)312     public static ParcelFileDescriptor fromFd(int fd) throws IOException {
313         final FileDescriptor original = new FileDescriptor();
314         original.setInt$(fd);
315 
316         try {
317             final FileDescriptor dup = Os.dup(original);
318             return new ParcelFileDescriptor(dup);
319         } catch (ErrnoException e) {
320             throw e.rethrowAsIOException();
321         }
322     }
323 
324     /**
325      * Take ownership of a raw native fd in to a new ParcelFileDescriptor.
326      * The returned ParcelFileDescriptor now owns the given fd, and will be
327      * responsible for closing it.  You must not close the fd yourself.
328      *
329      * @param fd The native fd that the ParcelFileDescriptor should adopt.
330      *
331      * @return Returns a new ParcelFileDescriptor holding a FileDescriptor
332      * for the given fd.
333      */
adoptFd(int fd)334     public static ParcelFileDescriptor adoptFd(int fd) {
335         final FileDescriptor fdesc = new FileDescriptor();
336         fdesc.setInt$(fd);
337 
338         return new ParcelFileDescriptor(fdesc);
339     }
340 
341     /**
342      * Create a new ParcelFileDescriptor from the specified Socket.  The new
343      * ParcelFileDescriptor holds a dup of the original FileDescriptor in
344      * the Socket, so you must still close the Socket as well as the new
345      * ParcelFileDescriptor.
346      *
347      * @param socket The Socket whose FileDescriptor is used to create
348      *               a new ParcelFileDescriptor.
349      *
350      * @return A new ParcelFileDescriptor with the FileDescriptor of the
351      *         specified Socket.
352      */
fromSocket(Socket socket)353     public static ParcelFileDescriptor fromSocket(Socket socket) {
354         FileDescriptor fd = socket.getFileDescriptor$();
355         return fd != null ? new ParcelFileDescriptor(fd) : null;
356     }
357 
358     /**
359      * Create a new ParcelFileDescriptor from the specified DatagramSocket.
360      *
361      * @param datagramSocket The DatagramSocket whose FileDescriptor is used
362      *               to create a new ParcelFileDescriptor.
363      *
364      * @return A new ParcelFileDescriptor with the FileDescriptor of the
365      *         specified DatagramSocket.
366      */
fromDatagramSocket(DatagramSocket datagramSocket)367     public static ParcelFileDescriptor fromDatagramSocket(DatagramSocket datagramSocket) {
368         FileDescriptor fd = datagramSocket.getFileDescriptor$();
369         return fd != null ? new ParcelFileDescriptor(fd) : null;
370     }
371 
372     /**
373      * Create two ParcelFileDescriptors structured as a data pipe.  The first
374      * ParcelFileDescriptor in the returned array is the read side; the second
375      * is the write side.
376      */
createPipe()377     public static ParcelFileDescriptor[] createPipe() throws IOException {
378         try {
379             final FileDescriptor[] fds = Os.pipe();
380             return new ParcelFileDescriptor[] {
381                     new ParcelFileDescriptor(fds[0]),
382                     new ParcelFileDescriptor(fds[1]) };
383         } catch (ErrnoException e) {
384             throw e.rethrowAsIOException();
385         }
386     }
387 
388     /**
389      * Create two ParcelFileDescriptors structured as a data pipe. The first
390      * ParcelFileDescriptor in the returned array is the read side; the second
391      * is the write side.
392      * <p>
393      * The write end has the ability to deliver an error message through
394      * {@link #closeWithError(String)} which can be handled by the read end
395      * calling {@link #checkError()}, usually after detecting an EOF.
396      * This can also be used to detect remote crashes.
397      */
createReliablePipe()398     public static ParcelFileDescriptor[] createReliablePipe() throws IOException {
399         try {
400             final FileDescriptor[] comm = createCommSocketPair();
401             final FileDescriptor[] fds = Os.pipe();
402             return new ParcelFileDescriptor[] {
403                     new ParcelFileDescriptor(fds[0], comm[0]),
404                     new ParcelFileDescriptor(fds[1], comm[1]) };
405         } catch (ErrnoException e) {
406             throw e.rethrowAsIOException();
407         }
408     }
409 
410     /**
411      * Create two ParcelFileDescriptors structured as a pair of sockets
412      * connected to each other. The two sockets are indistinguishable.
413      */
createSocketPair()414     public static ParcelFileDescriptor[] createSocketPair() throws IOException {
415         return createSocketPair(SOCK_STREAM);
416     }
417 
418     /**
419      * @hide
420      */
createSocketPair(int type)421     public static ParcelFileDescriptor[] createSocketPair(int type) throws IOException {
422         try {
423             final FileDescriptor fd0 = new FileDescriptor();
424             final FileDescriptor fd1 = new FileDescriptor();
425             Os.socketpair(AF_UNIX, type, 0, fd0, fd1);
426             return new ParcelFileDescriptor[] {
427                     new ParcelFileDescriptor(fd0),
428                     new ParcelFileDescriptor(fd1) };
429         } catch (ErrnoException e) {
430             throw e.rethrowAsIOException();
431         }
432     }
433 
434     /**
435      * Create two ParcelFileDescriptors structured as a pair of sockets
436      * connected to each other. The two sockets are indistinguishable.
437      * <p>
438      * Both ends have the ability to deliver an error message through
439      * {@link #closeWithError(String)} which can be detected by the other end
440      * calling {@link #checkError()}, usually after detecting an EOF.
441      * This can also be used to detect remote crashes.
442      */
createReliableSocketPair()443     public static ParcelFileDescriptor[] createReliableSocketPair() throws IOException {
444         return createReliableSocketPair(SOCK_STREAM);
445     }
446 
447     /**
448      * @hide
449      */
createReliableSocketPair(int type)450     public static ParcelFileDescriptor[] createReliableSocketPair(int type) throws IOException {
451         try {
452             final FileDescriptor[] comm = createCommSocketPair();
453             final FileDescriptor fd0 = new FileDescriptor();
454             final FileDescriptor fd1 = new FileDescriptor();
455             Os.socketpair(AF_UNIX, type, 0, fd0, fd1);
456             return new ParcelFileDescriptor[] {
457                     new ParcelFileDescriptor(fd0, comm[0]),
458                     new ParcelFileDescriptor(fd1, comm[1]) };
459         } catch (ErrnoException e) {
460             throw e.rethrowAsIOException();
461         }
462     }
463 
createCommSocketPair()464     private static FileDescriptor[] createCommSocketPair() throws IOException {
465         try {
466             // Use SOCK_SEQPACKET so that we have a guarantee that the status
467             // is written and read atomically as one unit and is not split
468             // across multiple IO operations.
469             final FileDescriptor comm1 = new FileDescriptor();
470             final FileDescriptor comm2 = new FileDescriptor();
471             Os.socketpair(AF_UNIX, SOCK_SEQPACKET, 0, comm1, comm2);
472             IoUtils.setBlocking(comm1, false);
473             IoUtils.setBlocking(comm2, false);
474             return new FileDescriptor[] { comm1, comm2 };
475         } catch (ErrnoException e) {
476             throw e.rethrowAsIOException();
477         }
478     }
479 
480     /**
481      * @hide Please use createPipe() or ContentProvider.openPipeHelper().
482      * Gets a file descriptor for a read-only copy of the given data.
483      *
484      * @param data Data to copy.
485      * @param name Name for the shared memory area that may back the file descriptor.
486      *        This is purely informative and may be {@code null}.
487      * @return A ParcelFileDescriptor.
488      * @throws IOException if there is an error while creating the shared memory area.
489      */
490     @Deprecated
fromData(byte[] data, String name)491     public static ParcelFileDescriptor fromData(byte[] data, String name) throws IOException {
492         if (data == null) return null;
493         MemoryFile file = new MemoryFile(name, data.length);
494         if (data.length > 0) {
495             file.writeBytes(data, 0, 0, data.length);
496         }
497         file.deactivate();
498         FileDescriptor fd = file.getFileDescriptor();
499         return fd != null ? new ParcelFileDescriptor(fd) : null;
500     }
501 
502     /**
503      * Converts a string representing a file mode, such as "rw", into a bitmask suitable for use
504      * with {@link #open}.
505      * <p>
506      * @param mode The string representation of the file mode.
507      * @return A bitmask representing the given file mode.
508      * @throws IllegalArgumentException if the given string does not match a known file mode.
509      */
parseMode(String mode)510     public static int parseMode(String mode) {
511         final int modeBits;
512         if ("r".equals(mode)) {
513             modeBits = ParcelFileDescriptor.MODE_READ_ONLY;
514         } else if ("w".equals(mode) || "wt".equals(mode)) {
515             modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
516                     | ParcelFileDescriptor.MODE_CREATE
517                     | ParcelFileDescriptor.MODE_TRUNCATE;
518         } else if ("wa".equals(mode)) {
519             modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
520                     | ParcelFileDescriptor.MODE_CREATE
521                     | ParcelFileDescriptor.MODE_APPEND;
522         } else if ("rw".equals(mode)) {
523             modeBits = ParcelFileDescriptor.MODE_READ_WRITE
524                     | ParcelFileDescriptor.MODE_CREATE;
525         } else if ("rwt".equals(mode)) {
526             modeBits = ParcelFileDescriptor.MODE_READ_WRITE
527                     | ParcelFileDescriptor.MODE_CREATE
528                     | ParcelFileDescriptor.MODE_TRUNCATE;
529         } else {
530             throw new IllegalArgumentException("Bad mode '" + mode + "'");
531         }
532         return modeBits;
533     }
534 
535     /**
536      * Retrieve the actual FileDescriptor associated with this object.
537      *
538      * @return Returns the FileDescriptor associated with this object.
539      */
getFileDescriptor()540     public FileDescriptor getFileDescriptor() {
541         if (mWrapped != null) {
542             return mWrapped.getFileDescriptor();
543         } else {
544             return mFd;
545         }
546     }
547 
548     /**
549      * Return the total size of the file representing this fd, as determined by
550      * {@code stat()}. Returns -1 if the fd is not a file.
551      */
getStatSize()552     public long getStatSize() {
553         if (mWrapped != null) {
554             return mWrapped.getStatSize();
555         } else {
556             try {
557                 final StructStat st = Os.fstat(mFd);
558                 if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
559                     return st.st_size;
560                 } else {
561                     return -1;
562                 }
563             } catch (ErrnoException e) {
564                 Log.w(TAG, "fstat() failed: " + e);
565                 return -1;
566             }
567         }
568     }
569 
570     /**
571      * This is needed for implementing AssetFileDescriptor.AutoCloseOutputStream,
572      * and I really don't think we want it to be public.
573      * @hide
574      */
seekTo(long pos)575     public long seekTo(long pos) throws IOException {
576         if (mWrapped != null) {
577             return mWrapped.seekTo(pos);
578         } else {
579             try {
580                 return Os.lseek(mFd, pos, SEEK_SET);
581             } catch (ErrnoException e) {
582                 throw e.rethrowAsIOException();
583             }
584         }
585     }
586 
587     /**
588      * Return the native fd int for this ParcelFileDescriptor.  The
589      * ParcelFileDescriptor still owns the fd, and it still must be closed
590      * through this API.
591      */
getFd()592     public int getFd() {
593         if (mWrapped != null) {
594             return mWrapped.getFd();
595         } else {
596             if (mClosed) {
597                 throw new IllegalStateException("Already closed");
598             }
599             return mFd.getInt$();
600         }
601     }
602 
603     /**
604      * Return the native fd int for this ParcelFileDescriptor and detach it from
605      * the object here. You are now responsible for closing the fd in native
606      * code.
607      * <p>
608      * You should not detach when the original creator of the descriptor is
609      * expecting a reliable signal through {@link #close()} or
610      * {@link #closeWithError(String)}.
611      *
612      * @see #canDetectErrors()
613      */
detachFd()614     public int detachFd() {
615         if (mWrapped != null) {
616             return mWrapped.detachFd();
617         } else {
618             if (mClosed) {
619                 throw new IllegalStateException("Already closed");
620             }
621             final int fd = getFd();
622             Parcel.clearFileDescriptor(mFd);
623             writeCommStatusAndClose(Status.DETACHED, null);
624             mClosed = true;
625             mGuard.close();
626             releaseResources();
627             return fd;
628         }
629     }
630 
631     /**
632      * Close the ParcelFileDescriptor. This implementation closes the underlying
633      * OS resources allocated to represent this stream.
634      *
635      * @throws IOException
636      *             If an error occurs attempting to close this ParcelFileDescriptor.
637      */
638     @Override
close()639     public void close() throws IOException {
640         if (mWrapped != null) {
641             try {
642                 mWrapped.close();
643             } finally {
644                 releaseResources();
645             }
646         } else {
647             closeWithStatus(Status.OK, null);
648         }
649     }
650 
651     /**
652      * Close the ParcelFileDescriptor, informing any peer that an error occurred
653      * while processing. If the creator of this descriptor is not observing
654      * errors, it will close normally.
655      *
656      * @param msg describing the error; must not be null.
657      */
closeWithError(String msg)658     public void closeWithError(String msg) throws IOException {
659         if (mWrapped != null) {
660             try {
661                 mWrapped.closeWithError(msg);
662             } finally {
663                 releaseResources();
664             }
665         } else {
666             if (msg == null) {
667                 throw new IllegalArgumentException("Message must not be null");
668             }
669             closeWithStatus(Status.ERROR, msg);
670         }
671     }
672 
closeWithStatus(int status, String msg)673     private void closeWithStatus(int status, String msg) {
674         if (mClosed) return;
675         mClosed = true;
676         mGuard.close();
677         // Status MUST be sent before closing actual descriptor
678         writeCommStatusAndClose(status, msg);
679         IoUtils.closeQuietly(mFd);
680         releaseResources();
681     }
682 
683     /**
684      * Called when the fd is being closed, for subclasses to release any other resources
685      * associated with it, such as acquired providers.
686      * @hide
687      */
releaseResources()688     public void releaseResources() {
689     }
690 
getOrCreateStatusBuffer()691     private byte[] getOrCreateStatusBuffer() {
692         if (mStatusBuf == null) {
693             mStatusBuf = new byte[MAX_STATUS];
694         }
695         return mStatusBuf;
696     }
697 
writeCommStatusAndClose(int status, String msg)698     private void writeCommStatusAndClose(int status, String msg) {
699         if (mCommFd == null) {
700             // Not reliable, or someone already sent status
701             if (msg != null) {
702                 Log.w(TAG, "Unable to inform peer: " + msg);
703             }
704             return;
705         }
706 
707         if (status == Status.DETACHED) {
708             Log.w(TAG, "Peer expected signal when closed; unable to deliver after detach");
709         }
710 
711         try {
712             if (status == Status.SILENCE) return;
713 
714             // Since we're about to close, read off any remote status. It's
715             // okay to remember missing here.
716             mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer());
717 
718             // Skip writing status when other end has already gone away.
719             if (mStatus != null) return;
720 
721             try {
722                 final byte[] buf = getOrCreateStatusBuffer();
723                 int writePtr = 0;
724 
725                 Memory.pokeInt(buf, writePtr, status, ByteOrder.BIG_ENDIAN);
726                 writePtr += 4;
727 
728                 if (msg != null) {
729                     final byte[] rawMsg = msg.getBytes();
730                     final int len = Math.min(rawMsg.length, buf.length - writePtr);
731                     System.arraycopy(rawMsg, 0, buf, writePtr, len);
732                     writePtr += len;
733                 }
734 
735                 // Must write the entire status as a single operation.
736                 Os.write(mCommFd, buf, 0, writePtr);
737             } catch (ErrnoException e) {
738                 // Reporting status is best-effort
739                 Log.w(TAG, "Failed to report status: " + e);
740             } catch (InterruptedIOException e) {
741                 // Reporting status is best-effort
742                 Log.w(TAG, "Failed to report status: " + e);
743             }
744 
745         } finally {
746             IoUtils.closeQuietly(mCommFd);
747             mCommFd = null;
748         }
749     }
750 
readCommStatus(FileDescriptor comm, byte[] buf)751     private static Status readCommStatus(FileDescriptor comm, byte[] buf) {
752         try {
753             // Must read the entire status as a single operation.
754             final int n = Os.read(comm, buf, 0, buf.length);
755             if (n == 0) {
756                 // EOF means they're dead
757                 return new Status(Status.DEAD);
758             } else {
759                 final int status = Memory.peekInt(buf, 0, ByteOrder.BIG_ENDIAN);
760                 if (status == Status.ERROR) {
761                     final String msg = new String(buf, 4, n - 4);
762                     return new Status(status, msg);
763                 }
764                 return new Status(status);
765             }
766         } catch (ErrnoException e) {
767             if (e.errno == OsConstants.EAGAIN) {
768                 // Remote is still alive, but no status written yet
769                 return null;
770             } else {
771                 Log.d(TAG, "Failed to read status; assuming dead: " + e);
772                 return new Status(Status.DEAD);
773             }
774         } catch (InterruptedIOException e) {
775             Log.d(TAG, "Failed to read status; assuming dead: " + e);
776             return new Status(Status.DEAD);
777         }
778     }
779 
780     /**
781      * Indicates if this ParcelFileDescriptor can communicate and detect remote
782      * errors/crashes.
783      *
784      * @see #checkError()
785      */
canDetectErrors()786     public boolean canDetectErrors() {
787         if (mWrapped != null) {
788             return mWrapped.canDetectErrors();
789         } else {
790             return mCommFd != null;
791         }
792     }
793 
794     /**
795      * Detect and throw if the other end of a pipe or socket pair encountered an
796      * error or crashed. This allows a reader to distinguish between a valid EOF
797      * and an error/crash.
798      * <p>
799      * If this ParcelFileDescriptor is unable to detect remote errors, it will
800      * return silently.
801      *
802      * @throws IOException for normal errors.
803      * @throws FileDescriptorDetachedException
804      *            if the remote side called {@link #detachFd()}. Once detached, the remote
805      *            side is unable to communicate any errors through
806      *            {@link #closeWithError(String)}.
807      * @see #canDetectErrors()
808      */
checkError()809     public void checkError() throws IOException {
810         if (mWrapped != null) {
811             mWrapped.checkError();
812         } else {
813             if (mStatus == null) {
814                 if (mCommFd == null) {
815                     Log.w(TAG, "Peer didn't provide a comm channel; unable to check for errors");
816                     return;
817                 }
818 
819                 // Try reading status; it might be null if nothing written yet.
820                 // Either way, we keep comm open to write our status later.
821                 mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer());
822             }
823 
824             if (mStatus == null || mStatus.status == Status.OK) {
825                 // No status yet, or everything is peachy!
826                 return;
827             } else {
828                 throw mStatus.asIOException();
829             }
830         }
831     }
832 
833     /**
834      * An InputStream you can create on a ParcelFileDescriptor, which will
835      * take care of calling {@link ParcelFileDescriptor#close
836      * ParcelFileDescriptor.close()} for you when the stream is closed.
837      */
838     public static class AutoCloseInputStream extends FileInputStream {
839         private final ParcelFileDescriptor mPfd;
840 
AutoCloseInputStream(ParcelFileDescriptor pfd)841         public AutoCloseInputStream(ParcelFileDescriptor pfd) {
842             super(pfd.getFileDescriptor());
843             mPfd = pfd;
844         }
845 
846         @Override
close()847         public void close() throws IOException {
848             try {
849                 mPfd.close();
850             } finally {
851                 super.close();
852             }
853         }
854     }
855 
856     /**
857      * An OutputStream you can create on a ParcelFileDescriptor, which will
858      * take care of calling {@link ParcelFileDescriptor#close
859      * ParcelFileDescriptor.close()} for you when the stream is closed.
860      */
861     public static class AutoCloseOutputStream extends FileOutputStream {
862         private final ParcelFileDescriptor mPfd;
863 
AutoCloseOutputStream(ParcelFileDescriptor pfd)864         public AutoCloseOutputStream(ParcelFileDescriptor pfd) {
865             super(pfd.getFileDescriptor());
866             mPfd = pfd;
867         }
868 
869         @Override
close()870         public void close() throws IOException {
871             try {
872                 mPfd.close();
873             } finally {
874                 super.close();
875             }
876         }
877     }
878 
879     @Override
toString()880     public String toString() {
881         if (mWrapped != null) {
882             return mWrapped.toString();
883         } else {
884             return "{ParcelFileDescriptor: " + mFd + "}";
885         }
886     }
887 
888     @Override
finalize()889     protected void finalize() throws Throwable {
890         if (mWrapped != null) {
891             releaseResources();
892         }
893         if (mGuard != null) {
894             mGuard.warnIfOpen();
895         }
896         try {
897             if (!mClosed) {
898                 closeWithStatus(Status.LEAKED, null);
899             }
900         } finally {
901             super.finalize();
902         }
903     }
904 
905     @Override
describeContents()906     public int describeContents() {
907         if (mWrapped != null) {
908             return mWrapped.describeContents();
909         } else {
910             return Parcelable.CONTENTS_FILE_DESCRIPTOR;
911         }
912     }
913 
914     /**
915      * {@inheritDoc}
916      * If {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set in flags,
917      * the file descriptor will be closed after a copy is written to the Parcel.
918      */
919     @Override
writeToParcel(Parcel out, int flags)920     public void writeToParcel(Parcel out, int flags) {
921         if (mWrapped != null) {
922             try {
923                 mWrapped.writeToParcel(out, flags);
924             } finally {
925                 releaseResources();
926             }
927         } else {
928             if (mCommFd != null) {
929                 out.writeInt(1);
930                 out.writeFileDescriptor(mFd);
931                 out.writeFileDescriptor(mCommFd);
932             } else {
933                 out.writeInt(0);
934                 out.writeFileDescriptor(mFd);
935             }
936             if ((flags & PARCELABLE_WRITE_RETURN_VALUE) != 0 && !mClosed) {
937                 // Not a real close, so emit no status
938                 closeWithStatus(Status.SILENCE, null);
939             }
940         }
941     }
942 
943     public static final Parcelable.Creator<ParcelFileDescriptor> CREATOR
944             = new Parcelable.Creator<ParcelFileDescriptor>() {
945         @Override
946         public ParcelFileDescriptor createFromParcel(Parcel in) {
947             int hasCommChannel = in.readInt();
948             final FileDescriptor fd = in.readRawFileDescriptor();
949             FileDescriptor commChannel = null;
950             if (hasCommChannel != 0) {
951                 commChannel = in.readRawFileDescriptor();
952             }
953             return new ParcelFileDescriptor(fd, commChannel);
954         }
955 
956         @Override
957         public ParcelFileDescriptor[] newArray(int size) {
958             return new ParcelFileDescriptor[size];
959         }
960     };
961 
962     /**
963      * Callback indicating that a ParcelFileDescriptor has been closed.
964      */
965     public interface OnCloseListener {
966         /**
967          * Event indicating the ParcelFileDescriptor to which this listener was
968          * attached has been closed.
969          *
970          * @param e error state, or {@code null} if closed cleanly.
971          *        If the close event was the result of
972          *        {@link ParcelFileDescriptor#detachFd()}, this will be a
973          *        {@link FileDescriptorDetachedException}. After detach the
974          *        remote side may continue reading/writing to the underlying
975          *        {@link FileDescriptor}, but they can no longer deliver
976          *        reliable close/error events.
977          */
onClose(IOException e)978         public void onClose(IOException e);
979     }
980 
981     /**
982      * Exception that indicates that the file descriptor was detached.
983      */
984     public static class FileDescriptorDetachedException extends IOException {
985 
986         private static final long serialVersionUID = 0xDe7ac4edFdL;
987 
FileDescriptorDetachedException()988         public FileDescriptorDetachedException() {
989             super("Remote side is detached");
990         }
991     }
992 
993     /**
994      * Internal class representing a remote status read by
995      * {@link ParcelFileDescriptor#readCommStatus(FileDescriptor, byte[])}.
996      */
997     private static class Status {
998         /** Special value indicating remote side died. */
999         public static final int DEAD = -2;
1000         /** Special value indicating no status should be written. */
1001         public static final int SILENCE = -1;
1002 
1003         /** Remote reported that everything went better than expected. */
1004         public static final int OK = 0;
1005         /** Remote reported error; length and message follow. */
1006         public static final int ERROR = 1;
1007         /** Remote reported {@link #detachFd()} and went rogue. */
1008         public static final int DETACHED = 2;
1009         /** Remote reported their object was finalized. */
1010         public static final int LEAKED = 3;
1011 
1012         public final int status;
1013         public final String msg;
1014 
Status(int status)1015         public Status(int status) {
1016             this(status, null);
1017         }
1018 
Status(int status, String msg)1019         public Status(int status, String msg) {
1020             this.status = status;
1021             this.msg = msg;
1022         }
1023 
asIOException()1024         public IOException asIOException() {
1025             switch (status) {
1026                 case DEAD:
1027                     return new IOException("Remote side is dead");
1028                 case OK:
1029                     return null;
1030                 case ERROR:
1031                     return new IOException("Remote error: " + msg);
1032                 case DETACHED:
1033                     return new FileDescriptorDetachedException();
1034                 case LEAKED:
1035                     return new IOException("Remote side was leaked");
1036                 default:
1037                     return new IOException("Unknown status: " + status);
1038             }
1039         }
1040 
1041         @Override
toString()1042         public String toString() {
1043             return "{" + status + ": " + msg + "}";
1044         }
1045     }
1046 }
1047