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