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