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             mFd.setInt$(-1);
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         if (mGuard != null) {
741             mGuard.close();
742         }
743         // Status MUST be sent before closing actual descriptor
744         writeCommStatusAndClose(status, msg);
745         IoUtils.closeQuietly(mFd);
746         releaseResources();
747     }
748 
749     /**
750      * Called when the fd is being closed, for subclasses to release any other resources
751      * associated with it, such as acquired providers.
752      * @hide
753      */
releaseResources()754     public void releaseResources() {
755     }
756 
getOrCreateStatusBuffer()757     private byte[] getOrCreateStatusBuffer() {
758         if (mStatusBuf == null) {
759             mStatusBuf = new byte[MAX_STATUS];
760         }
761         return mStatusBuf;
762     }
763 
writeCommStatusAndClose(int status, String msg)764     private void writeCommStatusAndClose(int status, String msg) {
765         if (mCommFd == null) {
766             // Not reliable, or someone already sent status
767             if (msg != null) {
768                 Log.w(TAG, "Unable to inform peer: " + msg);
769             }
770             return;
771         }
772 
773         if (status == Status.DETACHED) {
774             Log.w(TAG, "Peer expected signal when closed; unable to deliver after detach");
775         }
776 
777         try {
778             if (status == Status.SILENCE) return;
779 
780             // Since we're about to close, read off any remote status. It's
781             // okay to remember missing here.
782             mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer());
783 
784             // Skip writing status when other end has already gone away.
785             if (mStatus != null) return;
786 
787             try {
788                 final byte[] buf = getOrCreateStatusBuffer();
789                 int writePtr = 0;
790 
791                 Memory.pokeInt(buf, writePtr, status, ByteOrder.BIG_ENDIAN);
792                 writePtr += 4;
793 
794                 if (msg != null) {
795                     final byte[] rawMsg = msg.getBytes();
796                     final int len = Math.min(rawMsg.length, buf.length - writePtr);
797                     System.arraycopy(rawMsg, 0, buf, writePtr, len);
798                     writePtr += len;
799                 }
800 
801                 // Must write the entire status as a single operation.
802                 Os.write(mCommFd, buf, 0, writePtr);
803             } catch (ErrnoException e) {
804                 // Reporting status is best-effort
805                 Log.w(TAG, "Failed to report status: " + e);
806             } catch (InterruptedIOException e) {
807                 // Reporting status is best-effort
808                 Log.w(TAG, "Failed to report status: " + e);
809             }
810 
811         } finally {
812             IoUtils.closeQuietly(mCommFd);
813             mCommFd = null;
814         }
815     }
816 
readCommStatus(FileDescriptor comm, byte[] buf)817     private static Status readCommStatus(FileDescriptor comm, byte[] buf) {
818         try {
819             // Must read the entire status as a single operation.
820             final int n = Os.read(comm, buf, 0, buf.length);
821             if (n == 0) {
822                 // EOF means they're dead
823                 return new Status(Status.DEAD);
824             } else {
825                 final int status = Memory.peekInt(buf, 0, ByteOrder.BIG_ENDIAN);
826                 if (status == Status.ERROR) {
827                     final String msg = new String(buf, 4, n - 4);
828                     return new Status(status, msg);
829                 }
830                 return new Status(status);
831             }
832         } catch (ErrnoException e) {
833             if (e.errno == OsConstants.EAGAIN) {
834                 // Remote is still alive, but no status written yet
835                 return null;
836             } else {
837                 Log.d(TAG, "Failed to read status; assuming dead: " + e);
838                 return new Status(Status.DEAD);
839             }
840         } catch (InterruptedIOException e) {
841             Log.d(TAG, "Failed to read status; assuming dead: " + e);
842             return new Status(Status.DEAD);
843         }
844     }
845 
846     /**
847      * Indicates if this ParcelFileDescriptor can communicate and detect remote
848      * errors/crashes.
849      *
850      * @see #checkError()
851      */
canDetectErrors()852     public boolean canDetectErrors() {
853         if (mWrapped != null) {
854             return mWrapped.canDetectErrors();
855         } else {
856             return mCommFd != null;
857         }
858     }
859 
860     /**
861      * Detect and throw if the other end of a pipe or socket pair encountered an
862      * error or crashed. This allows a reader to distinguish between a valid EOF
863      * and an error/crash.
864      * <p>
865      * If this ParcelFileDescriptor is unable to detect remote errors, it will
866      * return silently.
867      *
868      * @throws IOException for normal errors.
869      * @throws FileDescriptorDetachedException
870      *            if the remote side called {@link #detachFd()}. Once detached, the remote
871      *            side is unable to communicate any errors through
872      *            {@link #closeWithError(String)}.
873      * @see #canDetectErrors()
874      */
checkError()875     public void checkError() throws IOException {
876         if (mWrapped != null) {
877             mWrapped.checkError();
878         } else {
879             if (mStatus == null) {
880                 if (mCommFd == null) {
881                     Log.w(TAG, "Peer didn't provide a comm channel; unable to check for errors");
882                     return;
883                 }
884 
885                 // Try reading status; it might be null if nothing written yet.
886                 // Either way, we keep comm open to write our status later.
887                 mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer());
888             }
889 
890             if (mStatus == null || mStatus.status == Status.OK) {
891                 // No status yet, or everything is peachy!
892                 return;
893             } else {
894                 throw mStatus.asIOException();
895             }
896         }
897     }
898 
899     /**
900      * An InputStream you can create on a ParcelFileDescriptor, which will
901      * take care of calling {@link ParcelFileDescriptor#close
902      * ParcelFileDescriptor.close()} for you when the stream is closed.
903      */
904     public static class AutoCloseInputStream extends FileInputStream {
905         private final ParcelFileDescriptor mPfd;
906 
AutoCloseInputStream(ParcelFileDescriptor pfd)907         public AutoCloseInputStream(ParcelFileDescriptor pfd) {
908             super(pfd.getFileDescriptor());
909             mPfd = pfd;
910         }
911 
912         @Override
close()913         public void close() throws IOException {
914             try {
915                 mPfd.close();
916             } finally {
917                 super.close();
918             }
919         }
920 
921         @Override
read()922         public int read() throws IOException {
923             final int result = super.read();
924             if (result == -1 && mPfd.canDetectErrors()) {
925                 // Check for errors only on EOF, to minimize overhead.
926                 mPfd.checkError();
927             }
928             return result;
929         }
930 
931         @Override
read(byte[] b)932         public int read(byte[] b) throws IOException {
933             final int result = super.read(b);
934             if (result == -1 && mPfd.canDetectErrors()) {
935                 mPfd.checkError();
936             }
937             return result;
938         }
939 
940         @Override
read(byte[] b, int off, int len)941         public int read(byte[] b, int off, int len) throws IOException {
942             final int result = super.read(b, off, len);
943             if (result == -1 && mPfd.canDetectErrors()) {
944                 mPfd.checkError();
945             }
946             return result;
947         }
948     }
949 
950     /**
951      * An OutputStream you can create on a ParcelFileDescriptor, which will
952      * take care of calling {@link ParcelFileDescriptor#close
953      * ParcelFileDescriptor.close()} for you when the stream is closed.
954      */
955     public static class AutoCloseOutputStream extends FileOutputStream {
956         private final ParcelFileDescriptor mPfd;
957 
AutoCloseOutputStream(ParcelFileDescriptor pfd)958         public AutoCloseOutputStream(ParcelFileDescriptor pfd) {
959             super(pfd.getFileDescriptor());
960             mPfd = pfd;
961         }
962 
963         @Override
close()964         public void close() throws IOException {
965             try {
966                 mPfd.close();
967             } finally {
968                 super.close();
969             }
970         }
971     }
972 
973     @Override
toString()974     public String toString() {
975         if (mWrapped != null) {
976             return mWrapped.toString();
977         } else {
978             return "{ParcelFileDescriptor: " + mFd + "}";
979         }
980     }
981 
982     @Override
finalize()983     protected void finalize() throws Throwable {
984         if (mWrapped != null) {
985             releaseResources();
986         }
987         if (mGuard != null) {
988             mGuard.warnIfOpen();
989         }
990         try {
991             if (!mClosed) {
992                 closeWithStatus(Status.LEAKED, null);
993             }
994         } finally {
995             super.finalize();
996         }
997     }
998 
999     @Override
describeContents()1000     public int describeContents() {
1001         if (mWrapped != null) {
1002             return mWrapped.describeContents();
1003         } else {
1004             return Parcelable.CONTENTS_FILE_DESCRIPTOR;
1005         }
1006     }
1007 
1008     /**
1009      * {@inheritDoc}
1010      * If {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set in flags,
1011      * the file descriptor will be closed after a copy is written to the Parcel.
1012      */
1013     @Override
writeToParcel(Parcel out, int flags)1014     public void writeToParcel(Parcel out, int flags) {
1015         if (mWrapped != null) {
1016             try {
1017                 mWrapped.writeToParcel(out, flags);
1018             } finally {
1019                 releaseResources();
1020             }
1021         } else {
1022             if (mCommFd != null) {
1023                 out.writeInt(1);
1024                 out.writeFileDescriptor(mFd);
1025                 out.writeFileDescriptor(mCommFd);
1026             } else {
1027                 out.writeInt(0);
1028                 out.writeFileDescriptor(mFd);
1029             }
1030             if ((flags & PARCELABLE_WRITE_RETURN_VALUE) != 0 && !mClosed) {
1031                 // Not a real close, so emit no status
1032                 closeWithStatus(Status.SILENCE, null);
1033             }
1034         }
1035     }
1036 
1037     public static final Parcelable.Creator<ParcelFileDescriptor> CREATOR
1038             = new Parcelable.Creator<ParcelFileDescriptor>() {
1039         @Override
1040         public ParcelFileDescriptor createFromParcel(Parcel in) {
1041             int hasCommChannel = in.readInt();
1042             final FileDescriptor fd = in.readRawFileDescriptor();
1043             FileDescriptor commChannel = null;
1044             if (hasCommChannel != 0) {
1045                 commChannel = in.readRawFileDescriptor();
1046             }
1047             return new ParcelFileDescriptor(fd, commChannel);
1048         }
1049 
1050         @Override
1051         public ParcelFileDescriptor[] newArray(int size) {
1052             return new ParcelFileDescriptor[size];
1053         }
1054     };
1055 
1056     /**
1057      * Callback indicating that a ParcelFileDescriptor has been closed.
1058      */
1059     public interface OnCloseListener {
1060         /**
1061          * Event indicating the ParcelFileDescriptor to which this listener was
1062          * attached has been closed.
1063          *
1064          * @param e error state, or {@code null} if closed cleanly.
1065          *        If the close event was the result of
1066          *        {@link ParcelFileDescriptor#detachFd()}, this will be a
1067          *        {@link FileDescriptorDetachedException}. After detach the
1068          *        remote side may continue reading/writing to the underlying
1069          *        {@link FileDescriptor}, but they can no longer deliver
1070          *        reliable close/error events.
1071          */
onClose(IOException e)1072         public void onClose(IOException e);
1073     }
1074 
1075     /**
1076      * Exception that indicates that the file descriptor was detached.
1077      */
1078     public static class FileDescriptorDetachedException extends IOException {
1079 
1080         private static final long serialVersionUID = 0xDe7ac4edFdL;
1081 
FileDescriptorDetachedException()1082         public FileDescriptorDetachedException() {
1083             super("Remote side is detached");
1084         }
1085     }
1086 
1087     /**
1088      * Internal class representing a remote status read by
1089      * {@link ParcelFileDescriptor#readCommStatus(FileDescriptor, byte[])}.
1090      */
1091     private static class Status {
1092         /** Special value indicating remote side died. */
1093         public static final int DEAD = -2;
1094         /** Special value indicating no status should be written. */
1095         public static final int SILENCE = -1;
1096 
1097         /** Remote reported that everything went better than expected. */
1098         public static final int OK = 0;
1099         /** Remote reported error; length and message follow. */
1100         public static final int ERROR = 1;
1101         /** Remote reported {@link #detachFd()} and went rogue. */
1102         public static final int DETACHED = 2;
1103         /** Remote reported their object was finalized. */
1104         public static final int LEAKED = 3;
1105 
1106         public final int status;
1107         public final String msg;
1108 
Status(int status)1109         public Status(int status) {
1110             this(status, null);
1111         }
1112 
Status(int status, String msg)1113         public Status(int status, String msg) {
1114             this.status = status;
1115             this.msg = msg;
1116         }
1117 
asIOException()1118         public IOException asIOException() {
1119             switch (status) {
1120                 case DEAD:
1121                     return new IOException("Remote side is dead");
1122                 case OK:
1123                     return null;
1124                 case ERROR:
1125                     return new IOException("Remote error: " + msg);
1126                 case DETACHED:
1127                     return new FileDescriptorDetachedException();
1128                 case LEAKED:
1129                     return new IOException("Remote side was leaked");
1130                 default:
1131                     return new IOException("Unknown status: " + status);
1132             }
1133         }
1134 
1135         @Override
toString()1136         public String toString() {
1137             return "{" + status + ": " + msg + "}";
1138         }
1139     }
1140 }
1141