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