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
17package android.os;
18
19import static android.system.OsConstants.AF_UNIX;
20import static android.system.OsConstants.O_APPEND;
21import static android.system.OsConstants.O_CREAT;
22import static android.system.OsConstants.O_RDONLY;
23import static android.system.OsConstants.O_RDWR;
24import static android.system.OsConstants.O_TRUNC;
25import static android.system.OsConstants.O_WRONLY;
26import static android.system.OsConstants.SEEK_SET;
27import static android.system.OsConstants.SOCK_SEQPACKET;
28import static android.system.OsConstants.SOCK_STREAM;
29import static android.system.OsConstants.S_IROTH;
30import static android.system.OsConstants.S_IRWXG;
31import static android.system.OsConstants.S_IRWXU;
32import static android.system.OsConstants.S_ISLNK;
33import static android.system.OsConstants.S_ISREG;
34import static android.system.OsConstants.S_IWOTH;
35
36import android.content.BroadcastReceiver;
37import android.content.ContentProvider;
38import android.os.MessageQueue.OnFileDescriptorEventListener;
39import android.system.ErrnoException;
40import android.system.Os;
41import android.system.OsConstants;
42import android.system.StructStat;
43import android.util.Log;
44
45import dalvik.system.CloseGuard;
46
47import libcore.io.IoUtils;
48import libcore.io.Memory;
49
50import java.io.Closeable;
51import java.io.File;
52import java.io.FileDescriptor;
53import java.io.FileInputStream;
54import java.io.FileNotFoundException;
55import java.io.FileOutputStream;
56import java.io.IOException;
57import java.io.InterruptedIOException;
58import java.net.DatagramSocket;
59import java.net.Socket;
60import java.nio.ByteOrder;
61
62/**
63 * The FileDescriptor returned by {@link Parcel#readFileDescriptor}, allowing
64 * you to close it when done with it.
65 */
66public 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     */
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} */
180    public ParcelFileDescriptor(FileDescriptor fd) {
181        this(fd, null);
182    }
183
184    /** {@hide} */
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     */
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     */
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} */
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
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
458    public static ParcelFileDescriptor[] createSocketPair() throws IOException {
459        return createSocketPair(SOCK_STREAM);
460    }
461
462    /**
463     * @hide
464     */
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     */
487    public static ParcelFileDescriptor[] createReliableSocketPair() throws IOException {
488        return createReliableSocketPair(SOCK_STREAM);
489    }
490
491    /**
492     * @hide
493     */
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
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
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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
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     */
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
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     */
754    public void releaseResources() {
755    }
756
757    private byte[] getOrCreateStatusBuffer() {
758        if (mStatusBuf == null) {
759            mStatusBuf = new byte[MAX_STATUS];
760        }
761        return mStatusBuf;
762    }
763
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
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     */
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     */
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
907        public AutoCloseInputStream(ParcelFileDescriptor pfd) {
908            super(pfd.getFileDescriptor());
909            mPfd = pfd;
910        }
911
912        @Override
913        public void close() throws IOException {
914            try {
915                mPfd.close();
916            } finally {
917                super.close();
918            }
919        }
920
921        @Override
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
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
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
958        public AutoCloseOutputStream(ParcelFileDescriptor pfd) {
959            super(pfd.getFileDescriptor());
960            mPfd = pfd;
961        }
962
963        @Override
964        public void close() throws IOException {
965            try {
966                mPfd.close();
967            } finally {
968                super.close();
969            }
970        }
971    }
972
973    @Override
974    public String toString() {
975        if (mWrapped != null) {
976            return mWrapped.toString();
977        } else {
978            return "{ParcelFileDescriptor: " + mFd + "}";
979        }
980    }
981
982    @Override
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
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
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         */
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
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
1109        public Status(int status) {
1110            this(status, null);
1111        }
1112
1113        public Status(int status, String msg) {
1114            this.status = status;
1115            this.msg = msg;
1116        }
1117
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
1136        public String toString() {
1137            return "{" + status + ": " + msg + "}";
1138        }
1139    }
1140}
1141