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