FileDocCategorySizeDatePackage
ParcelFileDescriptor.javaAPI DocAndroid 5.1 API37187Thu Mar 12 22:22:10 GMT 2015android.os

ParcelFileDescriptor

public class ParcelFileDescriptor extends Object implements Closeable, Parcelable
The FileDescriptor returned by {@link Parcel#readFileDescriptor}, allowing you to close it when done with it.

Fields Summary
private static final String
TAG
private final FileDescriptor
mFd
private FileDescriptor
mCommFd
Optional socket used to communicate close events, status at close, and detect remote process crashes.
private final ParcelFileDescriptor
mWrapped
Wrapped {@link ParcelFileDescriptor}, if any. Used to avoid double-closing {@link #mFd}.
private static final int
MAX_STATUS
Maximum {@link #mStatusBuf} size; longer status messages will be truncated.
private byte[]
mStatusBuf
Temporary buffer used by {@link #readCommStatus(FileDescriptor, byte[])}, allocated on-demand.
private Status
mStatus
Status read by {@link #checkError()}, or null if not read yet.
private volatile boolean
mClosed
private final dalvik.system.CloseGuard
mGuard
public static final int
MODE_WORLD_READABLE
For use with {@link #open}: if {@link #MODE_CREATE} has been supplied and this file doesn't already exist, then create the file with permissions such that any application can read it.
public static final int
MODE_WORLD_WRITEABLE
For use with {@link #open}: if {@link #MODE_CREATE} has been supplied and this file doesn't already exist, then create the file with permissions such that any application can write it.
public static final int
MODE_READ_ONLY
For use with {@link #open}: open the file with read-only access.
public static final int
MODE_WRITE_ONLY
For use with {@link #open}: open the file with write-only access.
public static final int
MODE_READ_WRITE
For use with {@link #open}: open the file with read and write access.
public static final int
MODE_CREATE
For use with {@link #open}: create the file if it doesn't already exist.
public static final int
MODE_TRUNCATE
For use with {@link #open}: erase contents of file when opening.
public static final int
MODE_APPEND
For use with {@link #open}: append to end of file while writing.
public static final Parcelable.Creator
CREATOR
Constructors Summary
public ParcelFileDescriptor(ParcelFileDescriptor wrapped)
Create a new ParcelFileDescriptor wrapped around another descriptor. By default all method calls are delegated to the wrapped descriptor.


                            
       
        // We keep a strong reference to the wrapped PFD, and rely on its
        // finalizer to trigger CloseGuard. All calls are delegated to wrapper.
        mWrapped = wrapped;
        mFd = null;
        mCommFd = null;
        mClosed = true;
    
public ParcelFileDescriptor(FileDescriptor fd)
{@hide}

        this(fd, null);
    
public ParcelFileDescriptor(FileDescriptor fd, FileDescriptor commChannel)
{@hide}

        if (fd == null) {
            throw new NullPointerException("FileDescriptor must not be null");
        }
        mWrapped = null;
        mFd = fd;
        mCommFd = commChannel;
        mGuard.open("close");
    
Methods Summary
public static android.os.ParcelFileDescriptoradoptFd(int fd)
Take ownership of a raw native fd in to a new ParcelFileDescriptor. The returned ParcelFileDescriptor now owns the given fd, and will be responsible for closing it. You must not close the fd yourself.

param
fd The native fd that the ParcelFileDescriptor should adopt.
return
Returns a new ParcelFileDescriptor holding a FileDescriptor for the given fd.

        final FileDescriptor fdesc = new FileDescriptor();
        fdesc.setInt$(fd);

        return new ParcelFileDescriptor(fdesc);
    
public booleancanDetectErrors()
Indicates if this ParcelFileDescriptor can communicate and detect remote errors/crashes.

see
#checkError()

        if (mWrapped != null) {
            return mWrapped.canDetectErrors();
        } else {
            return mCommFd != null;
        }
    
public voidcheckError()
Detect and throw if the other end of a pipe or socket pair encountered an error or crashed. This allows a reader to distinguish between a valid EOF and an error/crash.

If this ParcelFileDescriptor is unable to detect remote errors, it will return silently.

throws
IOException for normal errors.
throws
FileDescriptorDetachedException if the remote side called {@link #detachFd()}. Once detached, the remote side is unable to communicate any errors through {@link #closeWithError(String)}.
see
#canDetectErrors()

        if (mWrapped != null) {
            mWrapped.checkError();
        } else {
            if (mStatus == null) {
                if (mCommFd == null) {
                    Log.w(TAG, "Peer didn't provide a comm channel; unable to check for errors");
                    return;
                }

                // Try reading status; it might be null if nothing written yet.
                // Either way, we keep comm open to write our status later.
                mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer());
            }

            if (mStatus == null || mStatus.status == Status.OK) {
                // No status yet, or everything is peachy!
                return;
            } else {
                throw mStatus.asIOException();
            }
        }
    
public voidclose()
Close the ParcelFileDescriptor. This implementation closes the underlying OS resources allocated to represent this stream.

throws
IOException If an error occurs attempting to close this ParcelFileDescriptor.

        if (mWrapped != null) {
            try {
                mWrapped.close();
            } finally {
                releaseResources();
            }
        } else {
            closeWithStatus(Status.OK, null);
        }
    
public voidcloseWithError(java.lang.String msg)
Close the ParcelFileDescriptor, informing any peer that an error occurred while processing. If the creator of this descriptor is not observing errors, it will close normally.

param
msg describing the error; must not be null.

        if (mWrapped != null) {
            try {
                mWrapped.closeWithError(msg);
            } finally {
                releaseResources();
            }
        } else {
            if (msg == null) {
                throw new IllegalArgumentException("Message must not be null");
            }
            closeWithStatus(Status.ERROR, msg);
        }
    
private voidcloseWithStatus(int status, java.lang.String msg)

        if (mClosed) return;
        mClosed = true;
        mGuard.close();
        // Status MUST be sent before closing actual descriptor
        writeCommStatusAndClose(status, msg);
        IoUtils.closeQuietly(mFd);
        releaseResources();
    
private static java.io.FileDescriptor[]createCommSocketPair()

        try {
            final FileDescriptor comm1 = new FileDescriptor();
            final FileDescriptor comm2 = new FileDescriptor();
            Os.socketpair(AF_UNIX, SOCK_STREAM, 0, comm1, comm2);
            IoUtils.setBlocking(comm1, false);
            IoUtils.setBlocking(comm2, false);
            return new FileDescriptor[] { comm1, comm2 };
        } catch (ErrnoException e) {
            throw e.rethrowAsIOException();
        }
    
public static android.os.ParcelFileDescriptor[]createPipe()
Create two ParcelFileDescriptors structured as a data pipe. The first ParcelFileDescriptor in the returned array is the read side; the second is the write side.

        try {
            final FileDescriptor[] fds = Os.pipe();
            return new ParcelFileDescriptor[] {
                    new ParcelFileDescriptor(fds[0]),
                    new ParcelFileDescriptor(fds[1]) };
        } catch (ErrnoException e) {
            throw e.rethrowAsIOException();
        }
    
public static android.os.ParcelFileDescriptor[]createReliablePipe()
Create two ParcelFileDescriptors structured as a data pipe. The first ParcelFileDescriptor in the returned array is the read side; the second is the write side.

The write end has the ability to deliver an error message through {@link #closeWithError(String)} which can be handled by the read end calling {@link #checkError()}, usually after detecting an EOF. This can also be used to detect remote crashes.

        try {
            final FileDescriptor[] comm = createCommSocketPair();
            final FileDescriptor[] fds = Os.pipe();
            return new ParcelFileDescriptor[] {
                    new ParcelFileDescriptor(fds[0], comm[0]),
                    new ParcelFileDescriptor(fds[1], comm[1]) };
        } catch (ErrnoException e) {
            throw e.rethrowAsIOException();
        }
    
public static android.os.ParcelFileDescriptor[]createReliableSocketPair()
Create two ParcelFileDescriptors structured as a pair of sockets connected to each other. The two sockets are indistinguishable.

Both ends have the ability to deliver an error message through {@link #closeWithError(String)} which can be detected by the other end calling {@link #checkError()}, usually after detecting an EOF. This can also be used to detect remote crashes.

        try {
            final FileDescriptor[] comm = createCommSocketPair();
            final FileDescriptor fd0 = new FileDescriptor();
            final FileDescriptor fd1 = new FileDescriptor();
            Os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd0, fd1);
            return new ParcelFileDescriptor[] {
                    new ParcelFileDescriptor(fd0, comm[0]),
                    new ParcelFileDescriptor(fd1, comm[1]) };
        } catch (ErrnoException e) {
            throw e.rethrowAsIOException();
        }
    
public static android.os.ParcelFileDescriptor[]createSocketPair()
Create two ParcelFileDescriptors structured as a pair of sockets connected to each other. The two sockets are indistinguishable.

        try {
            final FileDescriptor fd0 = new FileDescriptor();
            final FileDescriptor fd1 = new FileDescriptor();
            Os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd0, fd1);
            return new ParcelFileDescriptor[] {
                    new ParcelFileDescriptor(fd0),
                    new ParcelFileDescriptor(fd1) };
        } catch (ErrnoException e) {
            throw e.rethrowAsIOException();
        }
    
public intdescribeContents()

        if (mWrapped != null) {
            return mWrapped.describeContents();
        } else {
            return Parcelable.CONTENTS_FILE_DESCRIPTOR;
        }
    
public intdetachFd()
Return the native fd int for this ParcelFileDescriptor and detach it from the object here. You are now responsible for closing the fd in native code.

You should not detach when the original creator of the descriptor is expecting a reliable signal through {@link #close()} or {@link #closeWithError(String)}.

see
#canDetectErrors()

        if (mWrapped != null) {
            return mWrapped.detachFd();
        } else {
            if (mClosed) {
                throw new IllegalStateException("Already closed");
            }
            final int fd = getFd();
            Parcel.clearFileDescriptor(mFd);
            writeCommStatusAndClose(Status.DETACHED, null);
            return fd;
        }
    
public static android.os.ParcelFileDescriptordup(java.io.FileDescriptor orig)
Create a new ParcelFileDescriptor that is a dup of an existing FileDescriptor. This obeys standard POSIX semantics, where the new file descriptor shared state such as file position with the original file descriptor.

        try {
            final FileDescriptor fd = Os.dup(orig);
            return new ParcelFileDescriptor(fd);
        } catch (ErrnoException e) {
            throw e.rethrowAsIOException();
        }
    
public android.os.ParcelFileDescriptordup()
Create a new ParcelFileDescriptor that is a dup of the existing FileDescriptor. This obeys standard POSIX semantics, where the new file descriptor shared state such as file position with the original file descriptor.

        if (mWrapped != null) {
            return mWrapped.dup();
        } else {
            return dup(getFileDescriptor());
        }
    
protected voidfinalize()

        if (mWrapped != null) {
            releaseResources();
        }
        if (mGuard != null) {
            mGuard.warnIfOpen();
        }
        try {
            if (!mClosed) {
                closeWithStatus(Status.LEAKED, null);
            }
        } finally {
            super.finalize();
        }
    
public static android.os.ParcelFileDescriptorfromData(byte[] data, java.lang.String name)

hide
Please use createPipe() or ContentProvider.openPipeHelper(). Gets a file descriptor for a read-only copy of the given data.
param
data Data to copy.
param
name Name for the shared memory area that may back the file descriptor. This is purely informative and may be {@code null}.
return
A ParcelFileDescriptor.
throws
IOException if there is an error while creating the shared memory area.

        if (data == null) return null;
        MemoryFile file = new MemoryFile(name, data.length);
        if (data.length > 0) {
            file.writeBytes(data, 0, 0, data.length);
        }
        file.deactivate();
        FileDescriptor fd = file.getFileDescriptor();
        return fd != null ? new ParcelFileDescriptor(fd) : null;
    
public static android.os.ParcelFileDescriptorfromDatagramSocket(java.net.DatagramSocket datagramSocket)
Create a new ParcelFileDescriptor from the specified DatagramSocket.

param
datagramSocket The DatagramSocket whose FileDescriptor is used to create a new ParcelFileDescriptor.
return
A new ParcelFileDescriptor with the FileDescriptor of the specified DatagramSocket.

        FileDescriptor fd = datagramSocket.getFileDescriptor$();
        return fd != null ? new ParcelFileDescriptor(fd) : null;
    
public static android.os.ParcelFileDescriptorfromFd(int fd)
Create a new ParcelFileDescriptor from a raw native fd. The new ParcelFileDescriptor holds a dup of the original fd passed in here, so you must still close that fd as well as the new ParcelFileDescriptor.

param
fd The native fd that the ParcelFileDescriptor should dup.
return
Returns a new ParcelFileDescriptor holding a FileDescriptor for a dup of the given fd.

        final FileDescriptor original = new FileDescriptor();
        original.setInt$(fd);

        try {
            final FileDescriptor dup = Os.dup(original);
            return new ParcelFileDescriptor(dup);
        } catch (ErrnoException e) {
            throw e.rethrowAsIOException();
        }
    
public static android.os.ParcelFileDescriptorfromSocket(java.net.Socket socket)
Create a new ParcelFileDescriptor from the specified Socket. The new ParcelFileDescriptor holds a dup of the original FileDescriptor in the Socket, so you must still close the Socket as well as the new ParcelFileDescriptor.

param
socket The Socket whose FileDescriptor is used to create a new ParcelFileDescriptor.
return
A new ParcelFileDescriptor with the FileDescriptor of the specified Socket.

        FileDescriptor fd = socket.getFileDescriptor$();
        return fd != null ? new ParcelFileDescriptor(fd) : null;
    
public intgetFd()
Return the native fd int for this ParcelFileDescriptor. The ParcelFileDescriptor still owns the fd, and it still must be closed through this API.

        if (mWrapped != null) {
            return mWrapped.getFd();
        } else {
            if (mClosed) {
                throw new IllegalStateException("Already closed");
            }
            return mFd.getInt$();
        }
    
public java.io.FileDescriptorgetFileDescriptor()
Retrieve the actual FileDescriptor associated with this object.

return
Returns the FileDescriptor associated with this object.

        if (mWrapped != null) {
            return mWrapped.getFileDescriptor();
        } else {
            return mFd;
        }
    
private byte[]getOrCreateStatusBuffer()

        if (mStatusBuf == null) {
            mStatusBuf = new byte[MAX_STATUS];
        }
        return mStatusBuf;
    
public longgetStatSize()
Return the total size of the file representing this fd, as determined by {@code stat()}. Returns -1 if the fd is not a file.

        if (mWrapped != null) {
            return mWrapped.getStatSize();
        } else {
            try {
                final StructStat st = Os.fstat(mFd);
                if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
                    return st.st_size;
                } else {
                    return -1;
                }
            } catch (ErrnoException e) {
                Log.w(TAG, "fstat() failed: " + e);
                return -1;
            }
        }
    
public static android.os.ParcelFileDescriptoropen(java.io.File file, int mode)
Create a new ParcelFileDescriptor accessing a given file.

param
file The file to be opened.
param
mode The desired access mode, must be one of {@link #MODE_READ_ONLY}, {@link #MODE_WRITE_ONLY}, or {@link #MODE_READ_WRITE}; may also be any combination of {@link #MODE_CREATE}, {@link #MODE_TRUNCATE}, {@link #MODE_WORLD_READABLE}, and {@link #MODE_WORLD_WRITEABLE}.
return
a new ParcelFileDescriptor pointing to the given file.
throws
FileNotFoundException if the given file does not exist or can not be opened with the requested mode.
see
#parseMode(String)

        final FileDescriptor fd = openInternal(file, mode);
        if (fd == null) return null;

        return new ParcelFileDescriptor(fd);
    
public static android.os.ParcelFileDescriptoropen(java.io.File file, int mode, Handler handler, android.os.ParcelFileDescriptor$OnCloseListener listener)
Create a new ParcelFileDescriptor accessing a given file.

param
file The file to be opened.
param
mode The desired access mode, must be one of {@link #MODE_READ_ONLY}, {@link #MODE_WRITE_ONLY}, or {@link #MODE_READ_WRITE}; may also be any combination of {@link #MODE_CREATE}, {@link #MODE_TRUNCATE}, {@link #MODE_WORLD_READABLE}, and {@link #MODE_WORLD_WRITEABLE}.
param
handler to call listener from; must not be null.
param
listener to be invoked when the returned descriptor has been closed; must not be null.
return
a new ParcelFileDescriptor pointing to the given file.
throws
FileNotFoundException if the given file does not exist or can not be opened with the requested mode.
see
#parseMode(String)

        if (handler == null) {
            throw new IllegalArgumentException("Handler must not be null");
        }
        if (listener == null) {
            throw new IllegalArgumentException("Listener must not be null");
        }

        final FileDescriptor fd = openInternal(file, mode);
        if (fd == null) return null;

        final FileDescriptor[] comm = createCommSocketPair();
        final ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd, comm[0]);

        // Kick off thread to watch for status updates
        IoUtils.setBlocking(comm[1], true);
        final ListenerBridge bridge = new ListenerBridge(comm[1], handler.getLooper(), listener);
        bridge.start();

        return pfd;
    
private static java.io.FileDescriptoropenInternal(java.io.File file, int mode)

        if ((mode & MODE_READ_WRITE) == 0) {
            throw new IllegalArgumentException(
                    "Must specify MODE_READ_ONLY, MODE_WRITE_ONLY, or MODE_READ_WRITE");
        }

        final String path = file.getPath();
        return Parcel.openFileDescriptor(path, mode);
    
public static intparseMode(java.lang.String mode)
Converts a string representing a file mode, such as "rw", into a bitmask suitable for use with {@link #open}.

param
mode The string representation of the file mode.
return
A bitmask representing the given file mode.
throws
IllegalArgumentException if the given string does not match a known file mode.

        final int modeBits;
        if ("r".equals(mode)) {
            modeBits = ParcelFileDescriptor.MODE_READ_ONLY;
        } else if ("w".equals(mode) || "wt".equals(mode)) {
            modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
                    | ParcelFileDescriptor.MODE_CREATE
                    | ParcelFileDescriptor.MODE_TRUNCATE;
        } else if ("wa".equals(mode)) {
            modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
                    | ParcelFileDescriptor.MODE_CREATE
                    | ParcelFileDescriptor.MODE_APPEND;
        } else if ("rw".equals(mode)) {
            modeBits = ParcelFileDescriptor.MODE_READ_WRITE
                    | ParcelFileDescriptor.MODE_CREATE;
        } else if ("rwt".equals(mode)) {
            modeBits = ParcelFileDescriptor.MODE_READ_WRITE
                    | ParcelFileDescriptor.MODE_CREATE
                    | ParcelFileDescriptor.MODE_TRUNCATE;
        } else {
            throw new IllegalArgumentException("Bad mode '" + mode + "'");
        }
        return modeBits;
    
private static android.os.ParcelFileDescriptor$StatusreadCommStatus(java.io.FileDescriptor comm, byte[] buf)

        try {
            final int n = Os.read(comm, buf, 0, buf.length);
            if (n == 0) {
                // EOF means they're dead
                return new Status(Status.DEAD);
            } else {
                final int status = Memory.peekInt(buf, 0, ByteOrder.BIG_ENDIAN);
                if (status == Status.ERROR) {
                    final String msg = new String(buf, 4, n - 4);
                    return new Status(status, msg);
                }
                return new Status(status);
            }
        } catch (ErrnoException e) {
            if (e.errno == OsConstants.EAGAIN) {
                // Remote is still alive, but no status written yet
                return null;
            } else {
                Log.d(TAG, "Failed to read status; assuming dead: " + e);
                return new Status(Status.DEAD);
            }
        } catch (InterruptedIOException e) {
            Log.d(TAG, "Failed to read status; assuming dead: " + e);
            return new Status(Status.DEAD);
        }
    
public voidreleaseResources()
Called when the fd is being closed, for subclasses to release any other resources associated with it, such as acquired providers.

hide

    
public longseekTo(long pos)
This is needed for implementing AssetFileDescriptor.AutoCloseOutputStream, and I really don't think we want it to be public.

hide

        if (mWrapped != null) {
            return mWrapped.seekTo(pos);
        } else {
            try {
                return Os.lseek(mFd, pos, SEEK_SET);
            } catch (ErrnoException e) {
                throw e.rethrowAsIOException();
            }
        }
    
public java.lang.StringtoString()

        if (mWrapped != null) {
            return mWrapped.toString();
        } else {
            return "{ParcelFileDescriptor: " + mFd + "}";
        }
    
private voidwriteCommStatusAndClose(int status, java.lang.String msg)

        if (mCommFd == null) {
            // Not reliable, or someone already sent status
            if (msg != null) {
                Log.w(TAG, "Unable to inform peer: " + msg);
            }
            return;
        }

        if (status == Status.DETACHED) {
            Log.w(TAG, "Peer expected signal when closed; unable to deliver after detach");
        }

        try {
            if (status == Status.SILENCE) return;

            // Since we're about to close, read off any remote status. It's
            // okay to remember missing here.
            mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer());

            // Skip writing status when other end has already gone away.
            if (mStatus != null) return;

            try {
                final byte[] buf = getOrCreateStatusBuffer();
                int writePtr = 0;

                Memory.pokeInt(buf, writePtr, status, ByteOrder.BIG_ENDIAN);
                writePtr += 4;

                if (msg != null) {
                    final byte[] rawMsg = msg.getBytes();
                    final int len = Math.min(rawMsg.length, buf.length - writePtr);
                    System.arraycopy(rawMsg, 0, buf, writePtr, len);
                    writePtr += len;
                }

                Os.write(mCommFd, buf, 0, writePtr);
            } catch (ErrnoException e) {
                // Reporting status is best-effort
                Log.w(TAG, "Failed to report status: " + e);
            } catch (InterruptedIOException e) {
                // Reporting status is best-effort
                Log.w(TAG, "Failed to report status: " + e);
            }

        } finally {
            IoUtils.closeQuietly(mCommFd);
            mCommFd = null;
        }
    
public voidwriteToParcel(Parcel out, int flags)
{@inheritDoc} If {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set in flags, the file descriptor will be closed after a copy is written to the Parcel.

        // WARNING: This must stay in sync with Parcel::readParcelFileDescriptor()
        // in frameworks/native/libs/binder/Parcel.cpp
        if (mWrapped != null) {
            try {
                mWrapped.writeToParcel(out, flags);
            } finally {
                releaseResources();
            }
        } else {
            out.writeFileDescriptor(mFd);
            if (mCommFd != null) {
                out.writeInt(1);
                out.writeFileDescriptor(mCommFd);
            } else {
                out.writeInt(0);
            }
            if ((flags & PARCELABLE_WRITE_RETURN_VALUE) != 0 && !mClosed) {
                // Not a real close, so emit no status
                closeWithStatus(Status.SILENCE, null);
            }
        }