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