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