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