ParcelFileDescriptor.java revision 3f6405259aab3d9d5bd0a1f6dec98ad27e774f69
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        final FileDescriptor[] comm = createCommSocketPair();
237        final ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd, comm[0]);
238        final MessageQueue queue = handler.getLooper().getQueue();
239        queue.addOnFileDescriptorEventListener(comm[1],
240                OnFileDescriptorEventListener.EVENT_INPUT, new OnFileDescriptorEventListener() {
241            @Override
242            public int onFileDescriptorEvents(FileDescriptor fd, int events) {
243                Status status = null;
244                if ((events & OnFileDescriptorEventListener.EVENT_INPUT) != 0) {
245                    final byte[] buf = new byte[MAX_STATUS];
246                    status = readCommStatus(fd, buf);
247                } else if ((events & OnFileDescriptorEventListener.EVENT_ERROR) != 0) {
248                    status = new Status(Status.DEAD);
249                }
250                if (status != null) {
251                    queue.removeOnFileDescriptorEventListener(fd);
252                    IoUtils.closeQuietly(fd);
253                    listener.onClose(status.asIOException());
254                    return 0;
255                }
256                return EVENT_INPUT;
257            }
258        });
259
260        return pfd;
261    }
262
263    private static FileDescriptor openInternal(File file, int mode) throws FileNotFoundException {
264        if ((mode & MODE_READ_WRITE) == 0) {
265            throw new IllegalArgumentException(
266                    "Must specify MODE_READ_ONLY, MODE_WRITE_ONLY, or MODE_READ_WRITE");
267        }
268
269        final String path = file.getPath();
270        return Parcel.openFileDescriptor(path, mode);
271    }
272
273    /**
274     * Create a new ParcelFileDescriptor that is a dup of an existing
275     * FileDescriptor.  This obeys standard POSIX semantics, where the
276     * new file descriptor shared state such as file position with the
277     * original file descriptor.
278     */
279    public static ParcelFileDescriptor dup(FileDescriptor orig) throws IOException {
280        try {
281            final FileDescriptor fd = Os.dup(orig);
282            return new ParcelFileDescriptor(fd);
283        } catch (ErrnoException e) {
284            throw e.rethrowAsIOException();
285        }
286    }
287
288    /**
289     * Create a new ParcelFileDescriptor that is a dup of the existing
290     * FileDescriptor.  This obeys standard POSIX semantics, where the
291     * new file descriptor shared state such as file position with the
292     * original file descriptor.
293     */
294    public ParcelFileDescriptor dup() throws IOException {
295        if (mWrapped != null) {
296            return mWrapped.dup();
297        } else {
298            return dup(getFileDescriptor());
299        }
300    }
301
302    /**
303     * Create a new ParcelFileDescriptor from a raw native fd.  The new
304     * ParcelFileDescriptor holds a dup of the original fd passed in here,
305     * so you must still close that fd as well as the new ParcelFileDescriptor.
306     *
307     * @param fd The native fd that the ParcelFileDescriptor should dup.
308     *
309     * @return Returns a new ParcelFileDescriptor holding a FileDescriptor
310     * for a dup of the given fd.
311     */
312    public static ParcelFileDescriptor fromFd(int fd) throws IOException {
313        final FileDescriptor original = new FileDescriptor();
314        original.setInt$(fd);
315
316        try {
317            final FileDescriptor dup = Os.dup(original);
318            return new ParcelFileDescriptor(dup);
319        } catch (ErrnoException e) {
320            throw e.rethrowAsIOException();
321        }
322    }
323
324    /**
325     * Take ownership of a raw native fd in to a new ParcelFileDescriptor.
326     * The returned ParcelFileDescriptor now owns the given fd, and will be
327     * responsible for closing it.  You must not close the fd yourself.
328     *
329     * @param fd The native fd that the ParcelFileDescriptor should adopt.
330     *
331     * @return Returns a new ParcelFileDescriptor holding a FileDescriptor
332     * for the given fd.
333     */
334    public static ParcelFileDescriptor adoptFd(int fd) {
335        final FileDescriptor fdesc = new FileDescriptor();
336        fdesc.setInt$(fd);
337
338        return new ParcelFileDescriptor(fdesc);
339    }
340
341    /**
342     * Create a new ParcelFileDescriptor from the specified Socket.  The new
343     * ParcelFileDescriptor holds a dup of the original FileDescriptor in
344     * the Socket, so you must still close the Socket as well as the new
345     * ParcelFileDescriptor.
346     *
347     * @param socket The Socket whose FileDescriptor is used to create
348     *               a new ParcelFileDescriptor.
349     *
350     * @return A new ParcelFileDescriptor with the FileDescriptor of the
351     *         specified Socket.
352     */
353    public static ParcelFileDescriptor fromSocket(Socket socket) {
354        FileDescriptor fd = socket.getFileDescriptor$();
355        return fd != null ? new ParcelFileDescriptor(fd) : null;
356    }
357
358    /**
359     * Create a new ParcelFileDescriptor from the specified DatagramSocket.
360     *
361     * @param datagramSocket The DatagramSocket whose FileDescriptor is used
362     *               to create a new ParcelFileDescriptor.
363     *
364     * @return A new ParcelFileDescriptor with the FileDescriptor of the
365     *         specified DatagramSocket.
366     */
367    public static ParcelFileDescriptor fromDatagramSocket(DatagramSocket datagramSocket) {
368        FileDescriptor fd = datagramSocket.getFileDescriptor$();
369        return fd != null ? new ParcelFileDescriptor(fd) : null;
370    }
371
372    /**
373     * Create two ParcelFileDescriptors structured as a data pipe.  The first
374     * ParcelFileDescriptor in the returned array is the read side; the second
375     * is the write side.
376     */
377    public static ParcelFileDescriptor[] createPipe() throws IOException {
378        try {
379            final FileDescriptor[] fds = Os.pipe();
380            return new ParcelFileDescriptor[] {
381                    new ParcelFileDescriptor(fds[0]),
382                    new ParcelFileDescriptor(fds[1]) };
383        } catch (ErrnoException e) {
384            throw e.rethrowAsIOException();
385        }
386    }
387
388    /**
389     * Create two ParcelFileDescriptors structured as a data pipe. The first
390     * ParcelFileDescriptor in the returned array is the read side; the second
391     * is the write side.
392     * <p>
393     * The write end has the ability to deliver an error message through
394     * {@link #closeWithError(String)} which can be handled by the read end
395     * calling {@link #checkError()}, usually after detecting an EOF.
396     * This can also be used to detect remote crashes.
397     */
398    public static ParcelFileDescriptor[] createReliablePipe() throws IOException {
399        try {
400            final FileDescriptor[] comm = createCommSocketPair();
401            final FileDescriptor[] fds = Os.pipe();
402            return new ParcelFileDescriptor[] {
403                    new ParcelFileDescriptor(fds[0], comm[0]),
404                    new ParcelFileDescriptor(fds[1], comm[1]) };
405        } catch (ErrnoException e) {
406            throw e.rethrowAsIOException();
407        }
408    }
409
410    /**
411     * Create two ParcelFileDescriptors structured as a pair of sockets
412     * connected to each other. The two sockets are indistinguishable.
413     */
414    public static ParcelFileDescriptor[] createSocketPair() throws IOException {
415        return createSocketPair(SOCK_STREAM);
416    }
417
418    /**
419     * @hide
420     */
421    public static ParcelFileDescriptor[] createSocketPair(int type) throws IOException {
422        try {
423            final FileDescriptor fd0 = new FileDescriptor();
424            final FileDescriptor fd1 = new FileDescriptor();
425            Os.socketpair(AF_UNIX, type, 0, fd0, fd1);
426            return new ParcelFileDescriptor[] {
427                    new ParcelFileDescriptor(fd0),
428                    new ParcelFileDescriptor(fd1) };
429        } catch (ErrnoException e) {
430            throw e.rethrowAsIOException();
431        }
432    }
433
434    /**
435     * Create two ParcelFileDescriptors structured as a pair of sockets
436     * connected to each other. The two sockets are indistinguishable.
437     * <p>
438     * Both ends have the ability to deliver an error message through
439     * {@link #closeWithError(String)} which can be detected by the other end
440     * calling {@link #checkError()}, usually after detecting an EOF.
441     * This can also be used to detect remote crashes.
442     */
443    public static ParcelFileDescriptor[] createReliableSocketPair() throws IOException {
444        return createReliableSocketPair(SOCK_STREAM);
445    }
446
447    /**
448     * @hide
449     */
450    public static ParcelFileDescriptor[] createReliableSocketPair(int type) throws IOException {
451        try {
452            final FileDescriptor[] comm = createCommSocketPair();
453            final FileDescriptor fd0 = new FileDescriptor();
454            final FileDescriptor fd1 = new FileDescriptor();
455            Os.socketpair(AF_UNIX, type, 0, fd0, fd1);
456            return new ParcelFileDescriptor[] {
457                    new ParcelFileDescriptor(fd0, comm[0]),
458                    new ParcelFileDescriptor(fd1, comm[1]) };
459        } catch (ErrnoException e) {
460            throw e.rethrowAsIOException();
461        }
462    }
463
464    private static FileDescriptor[] createCommSocketPair() throws IOException {
465        try {
466            // Use SOCK_SEQPACKET so that we have a guarantee that the status
467            // is written and read atomically as one unit and is not split
468            // across multiple IO operations.
469            final FileDescriptor comm1 = new FileDescriptor();
470            final FileDescriptor comm2 = new FileDescriptor();
471            Os.socketpair(AF_UNIX, SOCK_SEQPACKET, 0, comm1, comm2);
472            IoUtils.setBlocking(comm1, false);
473            IoUtils.setBlocking(comm2, false);
474            return new FileDescriptor[] { comm1, comm2 };
475        } catch (ErrnoException e) {
476            throw e.rethrowAsIOException();
477        }
478    }
479
480    /**
481     * @hide Please use createPipe() or ContentProvider.openPipeHelper().
482     * Gets a file descriptor for a read-only copy of the given data.
483     *
484     * @param data Data to copy.
485     * @param name Name for the shared memory area that may back the file descriptor.
486     *        This is purely informative and may be {@code null}.
487     * @return A ParcelFileDescriptor.
488     * @throws IOException if there is an error while creating the shared memory area.
489     */
490    @Deprecated
491    public static ParcelFileDescriptor fromData(byte[] data, String name) throws IOException {
492        if (data == null) return null;
493        MemoryFile file = new MemoryFile(name, data.length);
494        if (data.length > 0) {
495            file.writeBytes(data, 0, 0, data.length);
496        }
497        file.deactivate();
498        FileDescriptor fd = file.getFileDescriptor();
499        return fd != null ? new ParcelFileDescriptor(fd) : null;
500    }
501
502    /**
503     * Converts a string representing a file mode, such as "rw", into a bitmask suitable for use
504     * with {@link #open}.
505     * <p>
506     * @param mode The string representation of the file mode.
507     * @return A bitmask representing the given file mode.
508     * @throws IllegalArgumentException if the given string does not match a known file mode.
509     */
510    public static int parseMode(String mode) {
511        final int modeBits;
512        if ("r".equals(mode)) {
513            modeBits = ParcelFileDescriptor.MODE_READ_ONLY;
514        } else if ("w".equals(mode) || "wt".equals(mode)) {
515            modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
516                    | ParcelFileDescriptor.MODE_CREATE
517                    | ParcelFileDescriptor.MODE_TRUNCATE;
518        } else if ("wa".equals(mode)) {
519            modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
520                    | ParcelFileDescriptor.MODE_CREATE
521                    | ParcelFileDescriptor.MODE_APPEND;
522        } else if ("rw".equals(mode)) {
523            modeBits = ParcelFileDescriptor.MODE_READ_WRITE
524                    | ParcelFileDescriptor.MODE_CREATE;
525        } else if ("rwt".equals(mode)) {
526            modeBits = ParcelFileDescriptor.MODE_READ_WRITE
527                    | ParcelFileDescriptor.MODE_CREATE
528                    | ParcelFileDescriptor.MODE_TRUNCATE;
529        } else {
530            throw new IllegalArgumentException("Bad mode '" + mode + "'");
531        }
532        return modeBits;
533    }
534
535    /**
536     * Retrieve the actual FileDescriptor associated with this object.
537     *
538     * @return Returns the FileDescriptor associated with this object.
539     */
540    public FileDescriptor getFileDescriptor() {
541        if (mWrapped != null) {
542            return mWrapped.getFileDescriptor();
543        } else {
544            return mFd;
545        }
546    }
547
548    /**
549     * Return the total size of the file representing this fd, as determined by
550     * {@code stat()}. Returns -1 if the fd is not a file.
551     */
552    public long getStatSize() {
553        if (mWrapped != null) {
554            return mWrapped.getStatSize();
555        } else {
556            try {
557                final StructStat st = Os.fstat(mFd);
558                if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
559                    return st.st_size;
560                } else {
561                    return -1;
562                }
563            } catch (ErrnoException e) {
564                Log.w(TAG, "fstat() failed: " + e);
565                return -1;
566            }
567        }
568    }
569
570    /**
571     * This is needed for implementing AssetFileDescriptor.AutoCloseOutputStream,
572     * and I really don't think we want it to be public.
573     * @hide
574     */
575    public long seekTo(long pos) throws IOException {
576        if (mWrapped != null) {
577            return mWrapped.seekTo(pos);
578        } else {
579            try {
580                return Os.lseek(mFd, pos, SEEK_SET);
581            } catch (ErrnoException e) {
582                throw e.rethrowAsIOException();
583            }
584        }
585    }
586
587    /**
588     * Return the native fd int for this ParcelFileDescriptor.  The
589     * ParcelFileDescriptor still owns the fd, and it still must be closed
590     * through this API.
591     */
592    public int getFd() {
593        if (mWrapped != null) {
594            return mWrapped.getFd();
595        } else {
596            if (mClosed) {
597                throw new IllegalStateException("Already closed");
598            }
599            return mFd.getInt$();
600        }
601    }
602
603    /**
604     * Return the native fd int for this ParcelFileDescriptor and detach it from
605     * the object here. You are now responsible for closing the fd in native
606     * code.
607     * <p>
608     * You should not detach when the original creator of the descriptor is
609     * expecting a reliable signal through {@link #close()} or
610     * {@link #closeWithError(String)}.
611     *
612     * @see #canDetectErrors()
613     */
614    public int detachFd() {
615        if (mWrapped != null) {
616            return mWrapped.detachFd();
617        } else {
618            if (mClosed) {
619                throw new IllegalStateException("Already closed");
620            }
621            final int fd = getFd();
622            Parcel.clearFileDescriptor(mFd);
623            writeCommStatusAndClose(Status.DETACHED, null);
624            return fd;
625        }
626    }
627
628    /**
629     * Close the ParcelFileDescriptor. This implementation closes the underlying
630     * OS resources allocated to represent this stream.
631     *
632     * @throws IOException
633     *             If an error occurs attempting to close this ParcelFileDescriptor.
634     */
635    @Override
636    public void close() throws IOException {
637        if (mWrapped != null) {
638            try {
639                mWrapped.close();
640            } finally {
641                releaseResources();
642            }
643        } else {
644            closeWithStatus(Status.OK, null);
645        }
646    }
647
648    /**
649     * Close the ParcelFileDescriptor, informing any peer that an error occurred
650     * while processing. If the creator of this descriptor is not observing
651     * errors, it will close normally.
652     *
653     * @param msg describing the error; must not be null.
654     */
655    public void closeWithError(String msg) throws IOException {
656        if (mWrapped != null) {
657            try {
658                mWrapped.closeWithError(msg);
659            } finally {
660                releaseResources();
661            }
662        } else {
663            if (msg == null) {
664                throw new IllegalArgumentException("Message must not be null");
665            }
666            closeWithStatus(Status.ERROR, msg);
667        }
668    }
669
670    private void closeWithStatus(int status, String msg) {
671        if (mClosed) return;
672        mClosed = true;
673        mGuard.close();
674        // Status MUST be sent before closing actual descriptor
675        writeCommStatusAndClose(status, msg);
676        IoUtils.closeQuietly(mFd);
677        releaseResources();
678    }
679
680    /**
681     * Called when the fd is being closed, for subclasses to release any other resources
682     * associated with it, such as acquired providers.
683     * @hide
684     */
685    public void releaseResources() {
686    }
687
688    private byte[] getOrCreateStatusBuffer() {
689        if (mStatusBuf == null) {
690            mStatusBuf = new byte[MAX_STATUS];
691        }
692        return mStatusBuf;
693    }
694
695    private void writeCommStatusAndClose(int status, String msg) {
696        if (mCommFd == null) {
697            // Not reliable, or someone already sent status
698            if (msg != null) {
699                Log.w(TAG, "Unable to inform peer: " + msg);
700            }
701            return;
702        }
703
704        if (status == Status.DETACHED) {
705            Log.w(TAG, "Peer expected signal when closed; unable to deliver after detach");
706        }
707
708        try {
709            if (status == Status.SILENCE) return;
710
711            // Since we're about to close, read off any remote status. It's
712            // okay to remember missing here.
713            mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer());
714
715            // Skip writing status when other end has already gone away.
716            if (mStatus != null) return;
717
718            try {
719                final byte[] buf = getOrCreateStatusBuffer();
720                int writePtr = 0;
721
722                Memory.pokeInt(buf, writePtr, status, ByteOrder.BIG_ENDIAN);
723                writePtr += 4;
724
725                if (msg != null) {
726                    final byte[] rawMsg = msg.getBytes();
727                    final int len = Math.min(rawMsg.length, buf.length - writePtr);
728                    System.arraycopy(rawMsg, 0, buf, writePtr, len);
729                    writePtr += len;
730                }
731
732                // Must write the entire status as a single operation.
733                Os.write(mCommFd, buf, 0, writePtr);
734            } catch (ErrnoException e) {
735                // Reporting status is best-effort
736                Log.w(TAG, "Failed to report status: " + e);
737            } catch (InterruptedIOException e) {
738                // Reporting status is best-effort
739                Log.w(TAG, "Failed to report status: " + e);
740            }
741
742        } finally {
743            IoUtils.closeQuietly(mCommFd);
744            mCommFd = null;
745        }
746    }
747
748    private static Status readCommStatus(FileDescriptor comm, byte[] buf) {
749        try {
750            // Must read the entire status as a single operation.
751            final int n = Os.read(comm, buf, 0, buf.length);
752            if (n == 0) {
753                // EOF means they're dead
754                return new Status(Status.DEAD);
755            } else {
756                final int status = Memory.peekInt(buf, 0, ByteOrder.BIG_ENDIAN);
757                if (status == Status.ERROR) {
758                    final String msg = new String(buf, 4, n - 4);
759                    return new Status(status, msg);
760                }
761                return new Status(status);
762            }
763        } catch (ErrnoException e) {
764            if (e.errno == OsConstants.EAGAIN) {
765                // Remote is still alive, but no status written yet
766                return null;
767            } else {
768                Log.d(TAG, "Failed to read status; assuming dead: " + e);
769                return new Status(Status.DEAD);
770            }
771        } catch (InterruptedIOException e) {
772            Log.d(TAG, "Failed to read status; assuming dead: " + e);
773            return new Status(Status.DEAD);
774        }
775    }
776
777    /**
778     * Indicates if this ParcelFileDescriptor can communicate and detect remote
779     * errors/crashes.
780     *
781     * @see #checkError()
782     */
783    public boolean canDetectErrors() {
784        if (mWrapped != null) {
785            return mWrapped.canDetectErrors();
786        } else {
787            return mCommFd != null;
788        }
789    }
790
791    /**
792     * Detect and throw if the other end of a pipe or socket pair encountered an
793     * error or crashed. This allows a reader to distinguish between a valid EOF
794     * and an error/crash.
795     * <p>
796     * If this ParcelFileDescriptor is unable to detect remote errors, it will
797     * return silently.
798     *
799     * @throws IOException for normal errors.
800     * @throws FileDescriptorDetachedException
801     *            if the remote side called {@link #detachFd()}. Once detached, the remote
802     *            side is unable to communicate any errors through
803     *            {@link #closeWithError(String)}.
804     * @see #canDetectErrors()
805     */
806    public void checkError() throws IOException {
807        if (mWrapped != null) {
808            mWrapped.checkError();
809        } else {
810            if (mStatus == null) {
811                if (mCommFd == null) {
812                    Log.w(TAG, "Peer didn't provide a comm channel; unable to check for errors");
813                    return;
814                }
815
816                // Try reading status; it might be null if nothing written yet.
817                // Either way, we keep comm open to write our status later.
818                mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer());
819            }
820
821            if (mStatus == null || mStatus.status == Status.OK) {
822                // No status yet, or everything is peachy!
823                return;
824            } else {
825                throw mStatus.asIOException();
826            }
827        }
828    }
829
830    /**
831     * An InputStream you can create on a ParcelFileDescriptor, which will
832     * take care of calling {@link ParcelFileDescriptor#close
833     * ParcelFileDescriptor.close()} for you when the stream is closed.
834     */
835    public static class AutoCloseInputStream extends FileInputStream {
836        private final ParcelFileDescriptor mPfd;
837
838        public AutoCloseInputStream(ParcelFileDescriptor pfd) {
839            super(pfd.getFileDescriptor());
840            mPfd = pfd;
841        }
842
843        @Override
844        public void close() throws IOException {
845            try {
846                mPfd.close();
847            } finally {
848                super.close();
849            }
850        }
851    }
852
853    /**
854     * An OutputStream you can create on a ParcelFileDescriptor, which will
855     * take care of calling {@link ParcelFileDescriptor#close
856     * ParcelFileDescriptor.close()} for you when the stream is closed.
857     */
858    public static class AutoCloseOutputStream extends FileOutputStream {
859        private final ParcelFileDescriptor mPfd;
860
861        public AutoCloseOutputStream(ParcelFileDescriptor pfd) {
862            super(pfd.getFileDescriptor());
863            mPfd = pfd;
864        }
865
866        @Override
867        public void close() throws IOException {
868            try {
869                mPfd.close();
870            } finally {
871                super.close();
872            }
873        }
874    }
875
876    @Override
877    public String toString() {
878        if (mWrapped != null) {
879            return mWrapped.toString();
880        } else {
881            return "{ParcelFileDescriptor: " + mFd + "}";
882        }
883    }
884
885    @Override
886    protected void finalize() throws Throwable {
887        if (mWrapped != null) {
888            releaseResources();
889        }
890        if (mGuard != null) {
891            mGuard.warnIfOpen();
892        }
893        try {
894            if (!mClosed) {
895                closeWithStatus(Status.LEAKED, null);
896            }
897        } finally {
898            super.finalize();
899        }
900    }
901
902    @Override
903    public int describeContents() {
904        if (mWrapped != null) {
905            return mWrapped.describeContents();
906        } else {
907            return Parcelable.CONTENTS_FILE_DESCRIPTOR;
908        }
909    }
910
911    /**
912     * {@inheritDoc}
913     * If {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set in flags,
914     * the file descriptor will be closed after a copy is written to the Parcel.
915     */
916    @Override
917    public void writeToParcel(Parcel out, int flags) {
918        // WARNING: This must stay in sync with Parcel::readParcelFileDescriptor()
919        // in frameworks/native/libs/binder/Parcel.cpp
920        if (mWrapped != null) {
921            try {
922                mWrapped.writeToParcel(out, flags);
923            } finally {
924                releaseResources();
925            }
926        } else {
927            out.writeFileDescriptor(mFd);
928            if (mCommFd != null) {
929                out.writeInt(1);
930                out.writeFileDescriptor(mCommFd);
931            } else {
932                out.writeInt(0);
933            }
934            if ((flags & PARCELABLE_WRITE_RETURN_VALUE) != 0 && !mClosed) {
935                // Not a real close, so emit no status
936                closeWithStatus(Status.SILENCE, null);
937            }
938        }
939    }
940
941    public static final Parcelable.Creator<ParcelFileDescriptor> CREATOR
942            = new Parcelable.Creator<ParcelFileDescriptor>() {
943        @Override
944        public ParcelFileDescriptor createFromParcel(Parcel in) {
945            // WARNING: This must stay in sync with Parcel::writeParcelFileDescriptor()
946            // in frameworks/native/libs/binder/Parcel.cpp
947            final FileDescriptor fd = in.readRawFileDescriptor();
948            FileDescriptor commChannel = null;
949            if (in.readInt() != 0) {
950                commChannel = in.readRawFileDescriptor();
951            }
952            return new ParcelFileDescriptor(fd, commChannel);
953        }
954
955        @Override
956        public ParcelFileDescriptor[] newArray(int size) {
957            return new ParcelFileDescriptor[size];
958        }
959    };
960
961    /**
962     * Callback indicating that a ParcelFileDescriptor has been closed.
963     */
964    public interface OnCloseListener {
965        /**
966         * Event indicating the ParcelFileDescriptor to which this listener was
967         * attached has been closed.
968         *
969         * @param e error state, or {@code null} if closed cleanly.
970         *        If the close event was the result of
971         *        {@link ParcelFileDescriptor#detachFd()}, this will be a
972         *        {@link FileDescriptorDetachedException}. After detach the
973         *        remote side may continue reading/writing to the underlying
974         *        {@link FileDescriptor}, but they can no longer deliver
975         *        reliable close/error events.
976         */
977        public void onClose(IOException e);
978    }
979
980    /**
981     * Exception that indicates that the file descriptor was detached.
982     */
983    public static class FileDescriptorDetachedException extends IOException {
984
985        private static final long serialVersionUID = 0xDe7ac4edFdL;
986
987        public FileDescriptorDetachedException() {
988            super("Remote side is detached");
989        }
990    }
991
992    /**
993     * Internal class representing a remote status read by
994     * {@link ParcelFileDescriptor#readCommStatus(FileDescriptor, byte[])}.
995     */
996    private static class Status {
997        /** Special value indicating remote side died. */
998        public static final int DEAD = -2;
999        /** Special value indicating no status should be written. */
1000        public static final int SILENCE = -1;
1001
1002        /** Remote reported that everything went better than expected. */
1003        public static final int OK = 0;
1004        /** Remote reported error; length and message follow. */
1005        public static final int ERROR = 1;
1006        /** Remote reported {@link #detachFd()} and went rogue. */
1007        public static final int DETACHED = 2;
1008        /** Remote reported their object was finalized. */
1009        public static final int LEAKED = 3;
1010
1011        public final int status;
1012        public final String msg;
1013
1014        public Status(int status) {
1015            this(status, null);
1016        }
1017
1018        public Status(int status, String msg) {
1019            this.status = status;
1020            this.msg = msg;
1021        }
1022
1023        public IOException asIOException() {
1024            switch (status) {
1025                case DEAD:
1026                    return new IOException("Remote side is dead");
1027                case OK:
1028                    return null;
1029                case ERROR:
1030                    return new IOException("Remote error: " + msg);
1031                case DETACHED:
1032                    return new FileDescriptorDetachedException();
1033                case LEAKED:
1034                    return new IOException("Remote side was leaked");
1035                default:
1036                    return new IOException("Unknown status: " + status);
1037            }
1038        }
1039
1040        @Override
1041        public String toString() {
1042            return "{" + status + ": " + msg + "}";
1043        }
1044    }
1045}
1046