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             mFd.setInt$(-1);
    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         if (mGuard != null) {
    741             mGuard.close();
    742         }
    743         // Status MUST be sent before closing actual descriptor
    744         writeCommStatusAndClose(status, msg);
    745         IoUtils.closeQuietly(mFd);
    746         releaseResources();
    747     }
    748 
    749     /**
    750      * Called when the fd is being closed, for subclasses to release any other resources
    751      * associated with it, such as acquired providers.
    752      * @hide
    753      */
    754     public void releaseResources() {
    755     }
    756 
    757     private byte[] getOrCreateStatusBuffer() {
    758         if (mStatusBuf == null) {
    759             mStatusBuf = new byte[MAX_STATUS];
    760         }
    761         return mStatusBuf;
    762     }
    763 
    764     private void writeCommStatusAndClose(int status, String msg) {
    765         if (mCommFd == null) {
    766             // Not reliable, or someone already sent status
    767             if (msg != null) {
    768                 Log.w(TAG, "Unable to inform peer: " + msg);
    769             }
    770             return;
    771         }
    772 
    773         if (status == Status.DETACHED) {
    774             Log.w(TAG, "Peer expected signal when closed; unable to deliver after detach");
    775         }
    776 
    777         try {
    778             if (status == Status.SILENCE) return;
    779 
    780             // Since we're about to close, read off any remote status. It's
    781             // okay to remember missing here.
    782             mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer());
    783 
    784             // Skip writing status when other end has already gone away.
    785             if (mStatus != null) return;
    786 
    787             try {
    788                 final byte[] buf = getOrCreateStatusBuffer();
    789                 int writePtr = 0;
    790 
    791                 Memory.pokeInt(buf, writePtr, status, ByteOrder.BIG_ENDIAN);
    792                 writePtr += 4;
    793 
    794                 if (msg != null) {
    795                     final byte[] rawMsg = msg.getBytes();
    796                     final int len = Math.min(rawMsg.length, buf.length - writePtr);
    797                     System.arraycopy(rawMsg, 0, buf, writePtr, len);
    798                     writePtr += len;
    799                 }
    800 
    801                 // Must write the entire status as a single operation.
    802                 Os.write(mCommFd, buf, 0, writePtr);
    803             } catch (ErrnoException e) {
    804                 // Reporting status is best-effort
    805                 Log.w(TAG, "Failed to report status: " + e);
    806             } catch (InterruptedIOException e) {
    807                 // Reporting status is best-effort
    808                 Log.w(TAG, "Failed to report status: " + e);
    809             }
    810 
    811         } finally {
    812             IoUtils.closeQuietly(mCommFd);
    813             mCommFd = null;
    814         }
    815     }
    816 
    817     private static Status readCommStatus(FileDescriptor comm, byte[] buf) {
    818         try {
    819             // Must read the entire status as a single operation.
    820             final int n = Os.read(comm, buf, 0, buf.length);
    821             if (n == 0) {
    822                 // EOF means they're dead
    823                 return new Status(Status.DEAD);
    824             } else {
    825                 final int status = Memory.peekInt(buf, 0, ByteOrder.BIG_ENDIAN);
    826                 if (status == Status.ERROR) {
    827                     final String msg = new String(buf, 4, n - 4);
    828                     return new Status(status, msg);
    829                 }
    830                 return new Status(status);
    831             }
    832         } catch (ErrnoException e) {
    833             if (e.errno == OsConstants.EAGAIN) {
    834                 // Remote is still alive, but no status written yet
    835                 return null;
    836             } else {
    837                 Log.d(TAG, "Failed to read status; assuming dead: " + e);
    838                 return new Status(Status.DEAD);
    839             }
    840         } catch (InterruptedIOException e) {
    841             Log.d(TAG, "Failed to read status; assuming dead: " + e);
    842             return new Status(Status.DEAD);
    843         }
    844     }
    845 
    846     /**
    847      * Indicates if this ParcelFileDescriptor can communicate and detect remote
    848      * errors/crashes.
    849      *
    850      * @see #checkError()
    851      */
    852     public boolean canDetectErrors() {
    853         if (mWrapped != null) {
    854             return mWrapped.canDetectErrors();
    855         } else {
    856             return mCommFd != null;
    857         }
    858     }
    859 
    860     /**
    861      * Detect and throw if the other end of a pipe or socket pair encountered an
    862      * error or crashed. This allows a reader to distinguish between a valid EOF
    863      * and an error/crash.
    864      * <p>
    865      * If this ParcelFileDescriptor is unable to detect remote errors, it will
    866      * return silently.
    867      *
    868      * @throws IOException for normal errors.
    869      * @throws FileDescriptorDetachedException
    870      *            if the remote side called {@link #detachFd()}. Once detached, the remote
    871      *            side is unable to communicate any errors through
    872      *            {@link #closeWithError(String)}.
    873      * @see #canDetectErrors()
    874      */
    875     public void checkError() throws IOException {
    876         if (mWrapped != null) {
    877             mWrapped.checkError();
    878         } else {
    879             if (mStatus == null) {
    880                 if (mCommFd == null) {
    881                     Log.w(TAG, "Peer didn't provide a comm channel; unable to check for errors");
    882                     return;
    883                 }
    884 
    885                 // Try reading status; it might be null if nothing written yet.
    886                 // Either way, we keep comm open to write our status later.
    887                 mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer());
    888             }
    889 
    890             if (mStatus == null || mStatus.status == Status.OK) {
    891                 // No status yet, or everything is peachy!
    892                 return;
    893             } else {
    894                 throw mStatus.asIOException();
    895             }
    896         }
    897     }
    898 
    899     /**
    900      * An InputStream you can create on a ParcelFileDescriptor, which will
    901      * take care of calling {@link ParcelFileDescriptor#close
    902      * ParcelFileDescriptor.close()} for you when the stream is closed.
    903      */
    904     public static class AutoCloseInputStream extends FileInputStream {
    905         private final ParcelFileDescriptor mPfd;
    906 
    907         public AutoCloseInputStream(ParcelFileDescriptor pfd) {
    908             super(pfd.getFileDescriptor());
    909             mPfd = pfd;
    910         }
    911 
    912         @Override
    913         public void close() throws IOException {
    914             try {
    915                 mPfd.close();
    916             } finally {
    917                 super.close();
    918             }
    919         }
    920 
    921         @Override
    922         public int read() throws IOException {
    923             final int result = super.read();
    924             if (result == -1 && mPfd.canDetectErrors()) {
    925                 // Check for errors only on EOF, to minimize overhead.
    926                 mPfd.checkError();
    927             }
    928             return result;
    929         }
    930 
    931         @Override
    932         public int read(byte[] b) throws IOException {
    933             final int result = super.read(b);
    934             if (result == -1 && mPfd.canDetectErrors()) {
    935                 mPfd.checkError();
    936             }
    937             return result;
    938         }
    939 
    940         @Override
    941         public int read(byte[] b, int off, int len) throws IOException {
    942             final int result = super.read(b, off, len);
    943             if (result == -1 && mPfd.canDetectErrors()) {
    944                 mPfd.checkError();
    945             }
    946             return result;
    947         }
    948     }
    949 
    950     /**
    951      * An OutputStream you can create on a ParcelFileDescriptor, which will
    952      * take care of calling {@link ParcelFileDescriptor#close
    953      * ParcelFileDescriptor.close()} for you when the stream is closed.
    954      */
    955     public static class AutoCloseOutputStream extends FileOutputStream {
    956         private final ParcelFileDescriptor mPfd;
    957 
    958         public AutoCloseOutputStream(ParcelFileDescriptor pfd) {
    959             super(pfd.getFileDescriptor());
    960             mPfd = pfd;
    961         }
    962 
    963         @Override
    964         public void close() throws IOException {
    965             try {
    966                 mPfd.close();
    967             } finally {
    968                 super.close();
    969             }
    970         }
    971     }
    972 
    973     @Override
    974     public String toString() {
    975         if (mWrapped != null) {
    976             return mWrapped.toString();
    977         } else {
    978             return "{ParcelFileDescriptor: " + mFd + "}";
    979         }
    980     }
    981 
    982     @Override
    983     protected void finalize() throws Throwable {
    984         if (mWrapped != null) {
    985             releaseResources();
    986         }
    987         if (mGuard != null) {
    988             mGuard.warnIfOpen();
    989         }
    990         try {
    991             if (!mClosed) {
    992                 closeWithStatus(Status.LEAKED, null);
    993             }
    994         } finally {
    995             super.finalize();
    996         }
    997     }
    998 
    999     @Override
   1000     public int describeContents() {
   1001         if (mWrapped != null) {
   1002             return mWrapped.describeContents();
   1003         } else {
   1004             return Parcelable.CONTENTS_FILE_DESCRIPTOR;
   1005         }
   1006     }
   1007 
   1008     /**
   1009      * {@inheritDoc}
   1010      * If {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set in flags,
   1011      * the file descriptor will be closed after a copy is written to the Parcel.
   1012      */
   1013     @Override
   1014     public void writeToParcel(Parcel out, int flags) {
   1015         if (mWrapped != null) {
   1016             try {
   1017                 mWrapped.writeToParcel(out, flags);
   1018             } finally {
   1019                 releaseResources();
   1020             }
   1021         } else {
   1022             if (mCommFd != null) {
   1023                 out.writeInt(1);
   1024                 out.writeFileDescriptor(mFd);
   1025                 out.writeFileDescriptor(mCommFd);
   1026             } else {
   1027                 out.writeInt(0);
   1028                 out.writeFileDescriptor(mFd);
   1029             }
   1030             if ((flags & PARCELABLE_WRITE_RETURN_VALUE) != 0 && !mClosed) {
   1031                 // Not a real close, so emit no status
   1032                 closeWithStatus(Status.SILENCE, null);
   1033             }
   1034         }
   1035     }
   1036 
   1037     public static final Parcelable.Creator<ParcelFileDescriptor> CREATOR
   1038             = new Parcelable.Creator<ParcelFileDescriptor>() {
   1039         @Override
   1040         public ParcelFileDescriptor createFromParcel(Parcel in) {
   1041             int hasCommChannel = in.readInt();
   1042             final FileDescriptor fd = in.readRawFileDescriptor();
   1043             FileDescriptor commChannel = null;
   1044             if (hasCommChannel != 0) {
   1045                 commChannel = in.readRawFileDescriptor();
   1046             }
   1047             return new ParcelFileDescriptor(fd, commChannel);
   1048         }
   1049 
   1050         @Override
   1051         public ParcelFileDescriptor[] newArray(int size) {
   1052             return new ParcelFileDescriptor[size];
   1053         }
   1054     };
   1055 
   1056     /**
   1057      * Callback indicating that a ParcelFileDescriptor has been closed.
   1058      */
   1059     public interface OnCloseListener {
   1060         /**
   1061          * Event indicating the ParcelFileDescriptor to which this listener was
   1062          * attached has been closed.
   1063          *
   1064          * @param e error state, or {@code null} if closed cleanly.
   1065          *        If the close event was the result of
   1066          *        {@link ParcelFileDescriptor#detachFd()}, this will be a
   1067          *        {@link FileDescriptorDetachedException}. After detach the
   1068          *        remote side may continue reading/writing to the underlying
   1069          *        {@link FileDescriptor}, but they can no longer deliver
   1070          *        reliable close/error events.
   1071          */
   1072         public void onClose(IOException e);
   1073     }
   1074 
   1075     /**
   1076      * Exception that indicates that the file descriptor was detached.
   1077      */
   1078     public static class FileDescriptorDetachedException extends IOException {
   1079 
   1080         private static final long serialVersionUID = 0xDe7ac4edFdL;
   1081 
   1082         public FileDescriptorDetachedException() {
   1083             super("Remote side is detached");
   1084         }
   1085     }
   1086 
   1087     /**
   1088      * Internal class representing a remote status read by
   1089      * {@link ParcelFileDescriptor#readCommStatus(FileDescriptor, byte[])}.
   1090      */
   1091     private static class Status {
   1092         /** Special value indicating remote side died. */
   1093         public static final int DEAD = -2;
   1094         /** Special value indicating no status should be written. */
   1095         public static final int SILENCE = -1;
   1096 
   1097         /** Remote reported that everything went better than expected. */
   1098         public static final int OK = 0;
   1099         /** Remote reported error; length and message follow. */
   1100         public static final int ERROR = 1;
   1101         /** Remote reported {@link #detachFd()} and went rogue. */
   1102         public static final int DETACHED = 2;
   1103         /** Remote reported their object was finalized. */
   1104         public static final int LEAKED = 3;
   1105 
   1106         public final int status;
   1107         public final String msg;
   1108 
   1109         public Status(int status) {
   1110             this(status, null);
   1111         }
   1112 
   1113         public Status(int status, String msg) {
   1114             this.status = status;
   1115             this.msg = msg;
   1116         }
   1117 
   1118         public IOException asIOException() {
   1119             switch (status) {
   1120                 case DEAD:
   1121                     return new IOException("Remote side is dead");
   1122                 case OK:
   1123                     return null;
   1124                 case ERROR:
   1125                     return new IOException("Remote error: " + msg);
   1126                 case DETACHED:
   1127                     return new FileDescriptorDetachedException();
   1128                 case LEAKED:
   1129                     return new IOException("Remote side was leaked");
   1130                 default:
   1131                     return new IOException("Unknown status: " + status);
   1132             }
   1133         }
   1134 
   1135         @Override
   1136         public String toString() {
   1137             return "{" + status + ": " + msg + "}";
   1138         }
   1139     }
   1140 }
   1141