19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.os;
187407c948cbe7305c63ca33c471cf9e2a78674368Jeff Sharkey
19da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkeyimport static libcore.io.OsConstants.AF_UNIX;
20da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkeyimport static libcore.io.OsConstants.SEEK_SET;
21da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkeyimport static libcore.io.OsConstants.SOCK_STREAM;
22da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkeyimport static libcore.io.OsConstants.S_ISLNK;
23da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkeyimport static libcore.io.OsConstants.S_ISREG;
24da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
25da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkeyimport android.content.BroadcastReceiver;
26da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkeyimport android.content.ContentProvider;
27da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkeyimport android.util.Log;
28da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
297407c948cbe7305c63ca33c471cf9e2a78674368Jeff Sharkeyimport dalvik.system.CloseGuard;
307407c948cbe7305c63ca33c471cf9e2a78674368Jeff Sharkey
31da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkeyimport libcore.io.ErrnoException;
32da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkeyimport libcore.io.IoUtils;
33da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkeyimport libcore.io.Libcore;
34da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkeyimport libcore.io.Memory;
35da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkeyimport libcore.io.OsConstants;
36da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkeyimport libcore.io.StructStat;
37da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
38e861b423790e5bf2d5a55b096065c6ad0541d5bbJeff Sharkeyimport java.io.Closeable;
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.File;
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileDescriptor;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileInputStream;
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileNotFoundException;
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileOutputStream;
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException;
4547f8f0fa70343ea0d150e644f4109fb2d1185044Chia-chi Yehimport java.net.DatagramSocket;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.net.Socket;
47da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkeyimport java.nio.ByteOrder;
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The FileDescriptor returned by {@link Parcel#readFileDescriptor}, allowing
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you to close it when done with it.
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
53e861b423790e5bf2d5a55b096065c6ad0541d5bbJeff Sharkeypublic class ParcelFileDescriptor implements Parcelable, Closeable {
54da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    private static final String TAG = "ParcelFileDescriptor";
55da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
56da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    private final FileDescriptor mFd;
57da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
58da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    /**
59da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * Optional socket used to communicate close events, status at close, and
60da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * detect remote process crashes.
61da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     */
62da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    private FileDescriptor mCommFd;
637407c948cbe7305c63ca33c471cf9e2a78674368Jeff Sharkey
647407c948cbe7305c63ca33c471cf9e2a78674368Jeff Sharkey    /**
657407c948cbe7305c63ca33c471cf9e2a78674368Jeff Sharkey     * Wrapped {@link ParcelFileDescriptor}, if any. Used to avoid
66da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * double-closing {@link #mFd}.
677407c948cbe7305c63ca33c471cf9e2a78674368Jeff Sharkey     */
687407c948cbe7305c63ca33c471cf9e2a78674368Jeff Sharkey    private final ParcelFileDescriptor mWrapped;
697407c948cbe7305c63ca33c471cf9e2a78674368Jeff Sharkey
70da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    /**
71da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * Maximum {@link #mStatusBuf} size; longer status messages will be
72da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * truncated.
73da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     */
74da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    private static final int MAX_STATUS = 1024;
75da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
76da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    /**
77da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * Temporary buffer used by {@link #readCommStatus(FileDescriptor, byte[])},
78da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * allocated on-demand.
79da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     */
80da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    private byte[] mStatusBuf;
81da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
82da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    /**
83b433bb8c96f98d280f4a8508ba500bd8f196a773Amith Yamasani     * Status read by {@link #checkError()}, or null if not read yet.
84da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     */
85da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    private Status mStatus;
86da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
877407c948cbe7305c63ca33c471cf9e2a78674368Jeff Sharkey    private volatile boolean mClosed;
887407c948cbe7305c63ca33c471cf9e2a78674368Jeff Sharkey
897407c948cbe7305c63ca33c471cf9e2a78674368Jeff Sharkey    private final CloseGuard mGuard = CloseGuard.get();
904390758f277645de6e81f6482d582473383cc917Elliott Hughes
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
92da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied and
93da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * this file doesn't already exist, then create the file with permissions
94da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * such that any application can read it.
95da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     *
96da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * @deprecated Creating world-readable files is very dangerous, and likely
97da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     *             to cause security holes in applications. It is strongly
98da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     *             discouraged; instead, applications should use more formal
99da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     *             mechanism for interactions such as {@link ContentProvider},
100da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     *             {@link BroadcastReceiver}, and {@link android.app.Service}.
101da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     *             There are no guarantees that this access mode will remain on
102da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     *             a file, such as when it goes through a backup and restore.
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
104da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    @Deprecated
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int MODE_WORLD_READABLE = 0x00000001;
1064390758f277645de6e81f6482d582473383cc917Elliott Hughes
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
108da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied and
109da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * this file doesn't already exist, then create the file with permissions
110da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * such that any application can write it.
111da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     *
112da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * @deprecated Creating world-writable files is very dangerous, and likely
113da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     *             to cause security holes in applications. It is strongly
114da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     *             discouraged; instead, applications should use more formal
115da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     *             mechanism for interactions such as {@link ContentProvider},
116da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     *             {@link BroadcastReceiver}, and {@link android.app.Service}.
117da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     *             There are no guarantees that this access mode will remain on
118da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     *             a file, such as when it goes through a backup and restore.
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
120da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    @Deprecated
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int MODE_WORLD_WRITEABLE = 0x00000002;
1224390758f277645de6e81f6482d582473383cc917Elliott Hughes
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * For use with {@link #open}: open the file with read-only access.
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int MODE_READ_ONLY = 0x10000000;
1274390758f277645de6e81f6482d582473383cc917Elliott Hughes
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * For use with {@link #open}: open the file with write-only access.
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int MODE_WRITE_ONLY = 0x20000000;
1324390758f277645de6e81f6482d582473383cc917Elliott Hughes
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * For use with {@link #open}: open the file with read and write access.
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int MODE_READ_WRITE = 0x30000000;
1374390758f277645de6e81f6482d582473383cc917Elliott Hughes
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * For use with {@link #open}: create the file if it doesn't already exist.
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int MODE_CREATE = 0x08000000;
1424390758f277645de6e81f6482d582473383cc917Elliott Hughes
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * For use with {@link #open}: erase contents of file when opening.
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int MODE_TRUNCATE = 0x04000000;
1474390758f277645de6e81f6482d582473383cc917Elliott Hughes
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * For use with {@link #open}: append to end of file while writing.
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int MODE_APPEND = 0x02000000;
1524390758f277645de6e81f6482d582473383cc917Elliott Hughes
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
154da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * Create a new ParcelFileDescriptor wrapped around another descriptor. By
155da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * default all method calls are delegated to the wrapped descriptor.
156da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     */
157da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    public ParcelFileDescriptor(ParcelFileDescriptor wrapped) {
158da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        // We keep a strong reference to the wrapped PFD, and rely on its
159da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        // finalizer to trigger CloseGuard. All calls are delegated to wrapper.
160da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        mWrapped = wrapped;
161da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        mFd = null;
162da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        mCommFd = null;
163da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        mClosed = true;
164da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    }
165da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
166da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    /** {@hide} */
167da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    public ParcelFileDescriptor(FileDescriptor fd) {
168da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        this(fd, null);
169da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    }
170da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
171da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    /** {@hide} */
172da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    public ParcelFileDescriptor(FileDescriptor fd, FileDescriptor commChannel) {
173da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        if (fd == null) {
174da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            throw new NullPointerException("FileDescriptor must not be null");
175da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        }
176da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        mWrapped = null;
177da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        mFd = fd;
178da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        mCommFd = commChannel;
179da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        mGuard.open("close");
180da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    }
181da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
182da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    /**
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Create a new ParcelFileDescriptor accessing a given file.
1844390758f277645de6e81f6482d582473383cc917Elliott Hughes     *
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param file The file to be opened.
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param mode The desired access mode, must be one of
187da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     *            {@link #MODE_READ_ONLY}, {@link #MODE_WRITE_ONLY}, or
188da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     *            {@link #MODE_READ_WRITE}; may also be any combination of
189da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     *            {@link #MODE_CREATE}, {@link #MODE_TRUNCATE},
190da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     *            {@link #MODE_WORLD_READABLE}, and
191da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     *            {@link #MODE_WORLD_WRITEABLE}.
192da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * @return a new ParcelFileDescriptor pointing to the given file.
193da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * @throws FileNotFoundException if the given file does not exist or can not
194da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     *             be opened with the requested mode.
195e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * @see #parseMode(String)
196da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     */
197da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    public static ParcelFileDescriptor open(File file, int mode) throws FileNotFoundException {
198da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        final FileDescriptor fd = openInternal(file, mode);
199da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        if (fd == null) return null;
200da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
201da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        return new ParcelFileDescriptor(fd);
202da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    }
203da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
204da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    /**
205da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * Create a new ParcelFileDescriptor accessing a given file.
2064390758f277645de6e81f6482d582473383cc917Elliott Hughes     *
207da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * @param file The file to be opened.
208da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * @param mode The desired access mode, must be one of
209da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     *            {@link #MODE_READ_ONLY}, {@link #MODE_WRITE_ONLY}, or
210da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     *            {@link #MODE_READ_WRITE}; may also be any combination of
211da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     *            {@link #MODE_CREATE}, {@link #MODE_TRUNCATE},
212da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     *            {@link #MODE_WORLD_READABLE}, and
213da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     *            {@link #MODE_WORLD_WRITEABLE}.
214da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * @param handler to call listener from; must not be null.
215da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * @param listener to be invoked when the returned descriptor has been
216da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     *            closed; must not be null.
217da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * @return a new ParcelFileDescriptor pointing to the given file.
218da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * @throws FileNotFoundException if the given file does not exist or can not
219da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     *             be opened with the requested mode.
220e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * @see #parseMode(String)
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
222da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    public static ParcelFileDescriptor open(
223da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            File file, int mode, Handler handler, OnCloseListener listener) throws IOException {
224da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        if (handler == null) {
225da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            throw new IllegalArgumentException("Handler must not be null");
226da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        }
227da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        if (listener == null) {
228da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            throw new IllegalArgumentException("Listener must not be null");
229da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        }
230da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
231da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        final FileDescriptor fd = openInternal(file, mode);
232da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        if (fd == null) return null;
233da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
234d99f9caba6600f1b5e0bc8a21681162ae42d6518Jeff Sharkey        final FileDescriptor[] comm = createCommSocketPair();
235da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        final ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd, comm[0]);
236da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
237da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        // Kick off thread to watch for status updates
238d99f9caba6600f1b5e0bc8a21681162ae42d6518Jeff Sharkey        IoUtils.setBlocking(comm[1], true);
239da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        final ListenerBridge bridge = new ListenerBridge(comm[1], handler.getLooper(), listener);
240da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        bridge.start();
241da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
242da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        return pfd;
243da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    }
2444390758f277645de6e81f6482d582473383cc917Elliott Hughes
245da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    private static FileDescriptor openInternal(File file, int mode) throws FileNotFoundException {
246da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        if ((mode & MODE_READ_WRITE) == 0) {
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException(
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    "Must specify MODE_READ_ONLY, MODE_WRITE_ONLY, or MODE_READ_WRITE");
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2504390758f277645de6e81f6482d582473383cc917Elliott Hughes
251da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        final String path = file.getPath();
252da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        return Parcel.openFileDescriptor(path, mode);
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
256e17aeb31030cfeed339a39a107912ad5e9178390Dianne Hackborn     * Create a new ParcelFileDescriptor that is a dup of an existing
257e17aeb31030cfeed339a39a107912ad5e9178390Dianne Hackborn     * FileDescriptor.  This obeys standard POSIX semantics, where the
258e17aeb31030cfeed339a39a107912ad5e9178390Dianne Hackborn     * new file descriptor shared state such as file position with the
259e17aeb31030cfeed339a39a107912ad5e9178390Dianne Hackborn     * original file descriptor.
260e17aeb31030cfeed339a39a107912ad5e9178390Dianne Hackborn     */
261e17aeb31030cfeed339a39a107912ad5e9178390Dianne Hackborn    public static ParcelFileDescriptor dup(FileDescriptor orig) throws IOException {
262da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        try {
263da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            final FileDescriptor fd = Libcore.os.dup(orig);
264da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            return new ParcelFileDescriptor(fd);
265da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        } catch (ErrnoException e) {
266da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            throw e.rethrowAsIOException();
267da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        }
268e17aeb31030cfeed339a39a107912ad5e9178390Dianne Hackborn    }
269e17aeb31030cfeed339a39a107912ad5e9178390Dianne Hackborn
270e17aeb31030cfeed339a39a107912ad5e9178390Dianne Hackborn    /**
27162f20ecf492d2b29881bba307c79ff55e68760e6Dianne Hackborn     * Create a new ParcelFileDescriptor that is a dup of the existing
27262f20ecf492d2b29881bba307c79ff55e68760e6Dianne Hackborn     * FileDescriptor.  This obeys standard POSIX semantics, where the
27362f20ecf492d2b29881bba307c79ff55e68760e6Dianne Hackborn     * new file descriptor shared state such as file position with the
27462f20ecf492d2b29881bba307c79ff55e68760e6Dianne Hackborn     * original file descriptor.
27562f20ecf492d2b29881bba307c79ff55e68760e6Dianne Hackborn     */
27662f20ecf492d2b29881bba307c79ff55e68760e6Dianne Hackborn    public ParcelFileDescriptor dup() throws IOException {
277da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        if (mWrapped != null) {
278da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            return mWrapped.dup();
279da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        } else {
280da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            return dup(getFileDescriptor());
281da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        }
28262f20ecf492d2b29881bba307c79ff55e68760e6Dianne Hackborn    }
28362f20ecf492d2b29881bba307c79ff55e68760e6Dianne Hackborn
28462f20ecf492d2b29881bba307c79ff55e68760e6Dianne Hackborn    /**
285ea2117bdc03316a9292e2344c6fd157c85c13167Dianne Hackborn     * Create a new ParcelFileDescriptor from a raw native fd.  The new
286ea2117bdc03316a9292e2344c6fd157c85c13167Dianne Hackborn     * ParcelFileDescriptor holds a dup of the original fd passed in here,
287ea2117bdc03316a9292e2344c6fd157c85c13167Dianne Hackborn     * so you must still close that fd as well as the new ParcelFileDescriptor.
288ea2117bdc03316a9292e2344c6fd157c85c13167Dianne Hackborn     *
289ea2117bdc03316a9292e2344c6fd157c85c13167Dianne Hackborn     * @param fd The native fd that the ParcelFileDescriptor should dup.
290ea2117bdc03316a9292e2344c6fd157c85c13167Dianne Hackborn     *
291ea2117bdc03316a9292e2344c6fd157c85c13167Dianne Hackborn     * @return Returns a new ParcelFileDescriptor holding a FileDescriptor
292ea2117bdc03316a9292e2344c6fd157c85c13167Dianne Hackborn     * for a dup of the given fd.
293ea2117bdc03316a9292e2344c6fd157c85c13167Dianne Hackborn     */
294ea2117bdc03316a9292e2344c6fd157c85c13167Dianne Hackborn    public static ParcelFileDescriptor fromFd(int fd) throws IOException {
295da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        final FileDescriptor original = new FileDescriptor();
296da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        original.setInt$(fd);
297ea2117bdc03316a9292e2344c6fd157c85c13167Dianne Hackborn
298da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        try {
299da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            final FileDescriptor dup = Libcore.os.dup(original);
300da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            return new ParcelFileDescriptor(dup);
301da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        } catch (ErrnoException e) {
302da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            throw e.rethrowAsIOException();
303da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        }
304da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    }
305ea2117bdc03316a9292e2344c6fd157c85c13167Dianne Hackborn
306ea2117bdc03316a9292e2344c6fd157c85c13167Dianne Hackborn    /**
307ea2117bdc03316a9292e2344c6fd157c85c13167Dianne Hackborn     * Take ownership of a raw native fd in to a new ParcelFileDescriptor.
308ea2117bdc03316a9292e2344c6fd157c85c13167Dianne Hackborn     * The returned ParcelFileDescriptor now owns the given fd, and will be
309ea2117bdc03316a9292e2344c6fd157c85c13167Dianne Hackborn     * responsible for closing it.  You must not close the fd yourself.
310ea2117bdc03316a9292e2344c6fd157c85c13167Dianne Hackborn     *
311ea2117bdc03316a9292e2344c6fd157c85c13167Dianne Hackborn     * @param fd The native fd that the ParcelFileDescriptor should adopt.
312ea2117bdc03316a9292e2344c6fd157c85c13167Dianne Hackborn     *
313ea2117bdc03316a9292e2344c6fd157c85c13167Dianne Hackborn     * @return Returns a new ParcelFileDescriptor holding a FileDescriptor
314ea2117bdc03316a9292e2344c6fd157c85c13167Dianne Hackborn     * for the given fd.
315ea2117bdc03316a9292e2344c6fd157c85c13167Dianne Hackborn     */
316ea2117bdc03316a9292e2344c6fd157c85c13167Dianne Hackborn    public static ParcelFileDescriptor adoptFd(int fd) {
317da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        final FileDescriptor fdesc = new FileDescriptor();
318da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        fdesc.setInt$(fd);
319da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
320ea2117bdc03316a9292e2344c6fd157c85c13167Dianne Hackborn        return new ParcelFileDescriptor(fdesc);
321ea2117bdc03316a9292e2344c6fd157c85c13167Dianne Hackborn    }
322ea2117bdc03316a9292e2344c6fd157c85c13167Dianne Hackborn
323ea2117bdc03316a9292e2344c6fd157c85c13167Dianne Hackborn    /**
324ea2117bdc03316a9292e2344c6fd157c85c13167Dianne Hackborn     * Create a new ParcelFileDescriptor from the specified Socket.  The new
325ea2117bdc03316a9292e2344c6fd157c85c13167Dianne Hackborn     * ParcelFileDescriptor holds a dup of the original FileDescriptor in
326ea2117bdc03316a9292e2344c6fd157c85c13167Dianne Hackborn     * the Socket, so you must still close the Socket as well as the new
327ea2117bdc03316a9292e2344c6fd157c85c13167Dianne Hackborn     * ParcelFileDescriptor.
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param socket The Socket whose FileDescriptor is used to create
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *               a new ParcelFileDescriptor.
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return A new ParcelFileDescriptor with the FileDescriptor of the
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         specified Socket.
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static ParcelFileDescriptor fromSocket(Socket socket) {
3364390758f277645de6e81f6482d582473383cc917Elliott Hughes        FileDescriptor fd = socket.getFileDescriptor$();
337186683923ce8d6a2d5c6fd4768b26b90308661e9Dianne Hackborn        return fd != null ? new ParcelFileDescriptor(fd) : null;
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
34147f8f0fa70343ea0d150e644f4109fb2d1185044Chia-chi Yeh     * Create a new ParcelFileDescriptor from the specified DatagramSocket.
34247f8f0fa70343ea0d150e644f4109fb2d1185044Chia-chi Yeh     *
34347f8f0fa70343ea0d150e644f4109fb2d1185044Chia-chi Yeh     * @param datagramSocket The DatagramSocket whose FileDescriptor is used
34447f8f0fa70343ea0d150e644f4109fb2d1185044Chia-chi Yeh     *               to create a new ParcelFileDescriptor.
34547f8f0fa70343ea0d150e644f4109fb2d1185044Chia-chi Yeh     *
34647f8f0fa70343ea0d150e644f4109fb2d1185044Chia-chi Yeh     * @return A new ParcelFileDescriptor with the FileDescriptor of the
34747f8f0fa70343ea0d150e644f4109fb2d1185044Chia-chi Yeh     *         specified DatagramSocket.
34847f8f0fa70343ea0d150e644f4109fb2d1185044Chia-chi Yeh     */
34947f8f0fa70343ea0d150e644f4109fb2d1185044Chia-chi Yeh    public static ParcelFileDescriptor fromDatagramSocket(DatagramSocket datagramSocket) {
35047f8f0fa70343ea0d150e644f4109fb2d1185044Chia-chi Yeh        FileDescriptor fd = datagramSocket.getFileDescriptor$();
35147f8f0fa70343ea0d150e644f4109fb2d1185044Chia-chi Yeh        return fd != null ? new ParcelFileDescriptor(fd) : null;
35247f8f0fa70343ea0d150e644f4109fb2d1185044Chia-chi Yeh    }
35347f8f0fa70343ea0d150e644f4109fb2d1185044Chia-chi Yeh
35447f8f0fa70343ea0d150e644f4109fb2d1185044Chia-chi Yeh    /**
35523fdaf6fb62a9b5154b2508916a21c678462c5d0Dianne Hackborn     * Create two ParcelFileDescriptors structured as a data pipe.  The first
35623fdaf6fb62a9b5154b2508916a21c678462c5d0Dianne Hackborn     * ParcelFileDescriptor in the returned array is the read side; the second
35723fdaf6fb62a9b5154b2508916a21c678462c5d0Dianne Hackborn     * is the write side.
35823fdaf6fb62a9b5154b2508916a21c678462c5d0Dianne Hackborn     */
35923fdaf6fb62a9b5154b2508916a21c678462c5d0Dianne Hackborn    public static ParcelFileDescriptor[] createPipe() throws IOException {
360da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        try {
361da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            final FileDescriptor[] fds = Libcore.os.pipe();
362da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            return new ParcelFileDescriptor[] {
363da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                    new ParcelFileDescriptor(fds[0]),
364da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                    new ParcelFileDescriptor(fds[1]) };
365da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        } catch (ErrnoException e) {
366da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            throw e.rethrowAsIOException();
367da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        }
368da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    }
369da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
370da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    /**
371da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * Create two ParcelFileDescriptors structured as a data pipe. The first
372da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * ParcelFileDescriptor in the returned array is the read side; the second
373da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * is the write side.
374da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * <p>
375da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * The write end has the ability to deliver an error message through
376da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * {@link #closeWithError(String)} which can be handled by the read end
377b433bb8c96f98d280f4a8508ba500bd8f196a773Amith Yamasani     * calling {@link #checkError()}, usually after detecting an EOF.
378da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * This can also be used to detect remote crashes.
379da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     */
380da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    public static ParcelFileDescriptor[] createReliablePipe() throws IOException {
381da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        try {
382d99f9caba6600f1b5e0bc8a21681162ae42d6518Jeff Sharkey            final FileDescriptor[] comm = createCommSocketPair();
383da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            final FileDescriptor[] fds = Libcore.os.pipe();
384da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            return new ParcelFileDescriptor[] {
385da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                    new ParcelFileDescriptor(fds[0], comm[0]),
386da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                    new ParcelFileDescriptor(fds[1], comm[1]) };
387da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        } catch (ErrnoException e) {
388da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            throw e.rethrowAsIOException();
389da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        }
39023fdaf6fb62a9b5154b2508916a21c678462c5d0Dianne Hackborn    }
39123fdaf6fb62a9b5154b2508916a21c678462c5d0Dianne Hackborn
392da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    /**
393da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * Create two ParcelFileDescriptors structured as a pair of sockets
394da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * connected to each other. The two sockets are indistinguishable.
395da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     */
396da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    public static ParcelFileDescriptor[] createSocketPair() throws IOException {
397da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        try {
398da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            final FileDescriptor fd0 = new FileDescriptor();
399da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            final FileDescriptor fd1 = new FileDescriptor();
400da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            Libcore.os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd0, fd1);
401da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            return new ParcelFileDescriptor[] {
402da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                    new ParcelFileDescriptor(fd0),
403da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                    new ParcelFileDescriptor(fd1) };
404da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        } catch (ErrnoException e) {
405da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            throw e.rethrowAsIOException();
406da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        }
407da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    }
408da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
409da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    /**
410da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * Create two ParcelFileDescriptors structured as a pair of sockets
411da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * connected to each other. The two sockets are indistinguishable.
412da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * <p>
413da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * Both ends have the ability to deliver an error message through
414da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * {@link #closeWithError(String)} which can be detected by the other end
415b433bb8c96f98d280f4a8508ba500bd8f196a773Amith Yamasani     * calling {@link #checkError()}, usually after detecting an EOF.
416da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * This can also be used to detect remote crashes.
417da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     */
418da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    public static ParcelFileDescriptor[] createReliableSocketPair() throws IOException {
419da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        try {
420d99f9caba6600f1b5e0bc8a21681162ae42d6518Jeff Sharkey            final FileDescriptor[] comm = createCommSocketPair();
421da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            final FileDescriptor fd0 = new FileDescriptor();
422da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            final FileDescriptor fd1 = new FileDescriptor();
423da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            Libcore.os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd0, fd1);
424da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            return new ParcelFileDescriptor[] {
425da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                    new ParcelFileDescriptor(fd0, comm[0]),
426da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                    new ParcelFileDescriptor(fd1, comm[1]) };
427da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        } catch (ErrnoException e) {
428da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            throw e.rethrowAsIOException();
429da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        }
430da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    }
431da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
432d99f9caba6600f1b5e0bc8a21681162ae42d6518Jeff Sharkey    private static FileDescriptor[] createCommSocketPair() throws IOException {
433da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        try {
434da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            final FileDescriptor comm1 = new FileDescriptor();
435da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            final FileDescriptor comm2 = new FileDescriptor();
436da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            Libcore.os.socketpair(AF_UNIX, SOCK_STREAM, 0, comm1, comm2);
437d99f9caba6600f1b5e0bc8a21681162ae42d6518Jeff Sharkey            IoUtils.setBlocking(comm1, false);
438d99f9caba6600f1b5e0bc8a21681162ae42d6518Jeff Sharkey            IoUtils.setBlocking(comm2, false);
439da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            return new FileDescriptor[] { comm1, comm2 };
440da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        } catch (ErrnoException e) {
441da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            throw e.rethrowAsIOException();
442da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        }
443da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    }
44423fdaf6fb62a9b5154b2508916a21c678462c5d0Dianne Hackborn
44523fdaf6fb62a9b5154b2508916a21c678462c5d0Dianne Hackborn    /**
446540f86aa42877ac73f6f2f24dac49382432aa078Dianne Hackborn     * @hide Please use createPipe() or ContentProvider.openPipeHelper().
447a006b47298539d89dc7a06b54c070cb3e986352aBjorn Bringert     * Gets a file descriptor for a read-only copy of the given data.
448a006b47298539d89dc7a06b54c070cb3e986352aBjorn Bringert     *
449a006b47298539d89dc7a06b54c070cb3e986352aBjorn Bringert     * @param data Data to copy.
450a006b47298539d89dc7a06b54c070cb3e986352aBjorn Bringert     * @param name Name for the shared memory area that may back the file descriptor.
451a006b47298539d89dc7a06b54c070cb3e986352aBjorn Bringert     *        This is purely informative and may be {@code null}.
452a006b47298539d89dc7a06b54c070cb3e986352aBjorn Bringert     * @return A ParcelFileDescriptor.
453a006b47298539d89dc7a06b54c070cb3e986352aBjorn Bringert     * @throws IOException if there is an error while creating the shared memory area.
454a006b47298539d89dc7a06b54c070cb3e986352aBjorn Bringert     */
455a2ea747faaf5fcd437afbaaf4085cfc29e7c16b8Dianne Hackborn    @Deprecated
456a006b47298539d89dc7a06b54c070cb3e986352aBjorn Bringert    public static ParcelFileDescriptor fromData(byte[] data, String name) throws IOException {
457a006b47298539d89dc7a06b54c070cb3e986352aBjorn Bringert        if (data == null) return null;
458a006b47298539d89dc7a06b54c070cb3e986352aBjorn Bringert        MemoryFile file = new MemoryFile(name, data.length);
459a006b47298539d89dc7a06b54c070cb3e986352aBjorn Bringert        if (data.length > 0) {
460a006b47298539d89dc7a06b54c070cb3e986352aBjorn Bringert            file.writeBytes(data, 0, 0, data.length);
461a006b47298539d89dc7a06b54c070cb3e986352aBjorn Bringert        }
462a006b47298539d89dc7a06b54c070cb3e986352aBjorn Bringert        file.deactivate();
463a006b47298539d89dc7a06b54c070cb3e986352aBjorn Bringert        FileDescriptor fd = file.getFileDescriptor();
464a006b47298539d89dc7a06b54c070cb3e986352aBjorn Bringert        return fd != null ? new ParcelFileDescriptor(fd) : null;
465a006b47298539d89dc7a06b54c070cb3e986352aBjorn Bringert    }
466a006b47298539d89dc7a06b54c070cb3e986352aBjorn Bringert
467a006b47298539d89dc7a06b54c070cb3e986352aBjorn Bringert    /**
468eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski     * Converts a string representing a file mode, such as "rw", into a bitmask suitable for use
469eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski     * with {@link #open}.
470eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski     * <p>
471eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski     * @param mode The string representation of the file mode.
472eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski     * @return A bitmask representing the given file mode.
473eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski     * @throws IllegalArgumentException if the given string does not match a known file mode.
474eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski     */
475eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski    public static int parseMode(String mode) {
476eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski        final int modeBits;
477eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski        if ("r".equals(mode)) {
478eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski            modeBits = ParcelFileDescriptor.MODE_READ_ONLY;
479eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski        } else if ("w".equals(mode) || "wt".equals(mode)) {
480eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski            modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
481eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski                    | ParcelFileDescriptor.MODE_CREATE
482eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski                    | ParcelFileDescriptor.MODE_TRUNCATE;
483eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski        } else if ("wa".equals(mode)) {
484eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski            modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
485eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski                    | ParcelFileDescriptor.MODE_CREATE
486eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski                    | ParcelFileDescriptor.MODE_APPEND;
487eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski        } else if ("rw".equals(mode)) {
488eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski            modeBits = ParcelFileDescriptor.MODE_READ_WRITE
489eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski                    | ParcelFileDescriptor.MODE_CREATE;
490eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski        } else if ("rwt".equals(mode)) {
491eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski            modeBits = ParcelFileDescriptor.MODE_READ_WRITE
492eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski                    | ParcelFileDescriptor.MODE_CREATE
493eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski                    | ParcelFileDescriptor.MODE_TRUNCATE;
494eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski        } else {
495eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski            throw new IllegalArgumentException("Bad mode '" + mode + "'");
496eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski        }
497eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski        return modeBits;
498eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski    }
499eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski
500eb8c3f93edc826413ff4143284dec01c1061d5ccAdam Lesinski    /**
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Retrieve the actual FileDescriptor associated with this object.
5024390758f277645de6e81f6482d582473383cc917Elliott Hughes     *
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return Returns the FileDescriptor associated with this object.
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public FileDescriptor getFileDescriptor() {
506da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        if (mWrapped != null) {
507da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            return mWrapped.getFileDescriptor();
508da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        } else {
509da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            return mFd;
510da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        }
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5124390758f277645de6e81f6482d582473383cc917Elliott Hughes
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
514da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * Return the total size of the file representing this fd, as determined by
515da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * {@code stat()}. Returns -1 if the fd is not a file.
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
517da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    public long getStatSize() {
518da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        if (mWrapped != null) {
519da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            return mWrapped.getStatSize();
520da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        } else {
521da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            try {
522da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                final StructStat st = Libcore.os.fstat(mFd);
523da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
524da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                    return st.st_size;
525da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                } else {
526da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                    return -1;
527da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                }
528da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            } catch (ErrnoException e) {
529da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                Log.w(TAG, "fstat() failed: " + e);
530da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                return -1;
531da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            }
532da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        }
533da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    }
5344390758f277645de6e81f6482d582473383cc917Elliott Hughes
5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This is needed for implementing AssetFileDescriptor.AutoCloseOutputStream,
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * and I really don't think we want it to be public.
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @hide
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
540da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    public long seekTo(long pos) throws IOException {
541da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        if (mWrapped != null) {
542da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            return mWrapped.seekTo(pos);
543da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        } else {
544da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            try {
545da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                return Libcore.os.lseek(mFd, pos, SEEK_SET);
546da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            } catch (ErrnoException e) {
547da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                throw e.rethrowAsIOException();
548da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            }
549da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        }
550da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    }
5514390758f277645de6e81f6482d582473383cc917Elliott Hughes
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
553c9119f5034d36f548bbddd8f60291e24ab4e270bDianne Hackborn     * Return the native fd int for this ParcelFileDescriptor.  The
554c9119f5034d36f548bbddd8f60291e24ab4e270bDianne Hackborn     * ParcelFileDescriptor still owns the fd, and it still must be closed
555c9119f5034d36f548bbddd8f60291e24ab4e270bDianne Hackborn     * through this API.
556c9119f5034d36f548bbddd8f60291e24ab4e270bDianne Hackborn     */
557c9119f5034d36f548bbddd8f60291e24ab4e270bDianne Hackborn    public int getFd() {
558da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        if (mWrapped != null) {
559da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            return mWrapped.getFd();
560da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        } else {
561da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            if (mClosed) {
562da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                throw new IllegalStateException("Already closed");
563da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            }
564da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            return mFd.getInt$();
565c9119f5034d36f548bbddd8f60291e24ab4e270bDianne Hackborn        }
566c9119f5034d36f548bbddd8f60291e24ab4e270bDianne Hackborn    }
5674390758f277645de6e81f6482d582473383cc917Elliott Hughes
568c9119f5034d36f548bbddd8f60291e24ab4e270bDianne Hackborn    /**
569da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * Return the native fd int for this ParcelFileDescriptor and detach it from
570da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * the object here. You are now responsible for closing the fd in native
571da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * code.
572da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * <p>
573da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * You should not detach when the original creator of the descriptor is
574da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * expecting a reliable signal through {@link #close()} or
575da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * {@link #closeWithError(String)}.
576da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     *
577da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * @see #canDetectErrors()
578c9119f5034d36f548bbddd8f60291e24ab4e270bDianne Hackborn     */
579c9119f5034d36f548bbddd8f60291e24ab4e270bDianne Hackborn    public int detachFd() {
5807407c948cbe7305c63ca33c471cf9e2a78674368Jeff Sharkey        if (mWrapped != null) {
581da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            return mWrapped.detachFd();
582da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        } else {
583da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            if (mClosed) {
584da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                throw new IllegalStateException("Already closed");
585da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            }
586da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            final int fd = getFd();
587da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            Parcel.clearFileDescriptor(mFd);
588da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            writeCommStatusAndClose(Status.DETACHED, null);
589c9119f5034d36f548bbddd8f60291e24ab4e270bDianne Hackborn            return fd;
590c9119f5034d36f548bbddd8f60291e24ab4e270bDianne Hackborn        }
591c9119f5034d36f548bbddd8f60291e24ab4e270bDianne Hackborn    }
5924390758f277645de6e81f6482d582473383cc917Elliott Hughes
593c9119f5034d36f548bbddd8f60291e24ab4e270bDianne Hackborn    /**
5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Close the ParcelFileDescriptor. This implementation closes the underlying
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * OS resources allocated to represent this stream.
5964390758f277645de6e81f6482d582473383cc917Elliott Hughes     *
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws IOException
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *             If an error occurs attempting to close this ParcelFileDescriptor.
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6007407c948cbe7305c63ca33c471cf9e2a78674368Jeff Sharkey    @Override
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void close() throws IOException {
6027407c948cbe7305c63ca33c471cf9e2a78674368Jeff Sharkey        if (mWrapped != null) {
603487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani            try {
604487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani                mWrapped.close();
605487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani            } finally {
606487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani                releaseResources();
607487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani            }
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
609da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            closeWithStatus(Status.OK, null);
610da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        }
611da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    }
612da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
613da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    /**
614da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * Close the ParcelFileDescriptor, informing any peer that an error occurred
615da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * while processing. If the creator of this descriptor is not observing
616da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * errors, it will close normally.
617da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     *
618da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * @param msg describing the error; must not be null.
619da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     */
620da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    public void closeWithError(String msg) throws IOException {
621da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        if (mWrapped != null) {
622487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani            try {
623487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani                mWrapped.closeWithError(msg);
624487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani            } finally {
625487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani                releaseResources();
626487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani            }
627da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        } else {
628da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            if (msg == null) {
629da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                throw new IllegalArgumentException("Message must not be null");
630da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            }
631da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            closeWithStatus(Status.ERROR, msg);
632da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        }
633da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    }
634da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
635487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani    private void closeWithStatus(int status, String msg) {
636487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani        if (mClosed) return;
637487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani        mClosed = true;
638487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani        mGuard.close();
639487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani        // Status MUST be sent before closing actual descriptor
640487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani        writeCommStatusAndClose(status, msg);
641487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani        IoUtils.closeQuietly(mFd);
642487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani        releaseResources();
643487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani    }
644487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani
645487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani    /**
646487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani     * Called when the fd is being closed, for subclasses to release any other resources
647487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani     * associated with it, such as acquired providers.
648487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani     * @hide
649487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani     */
650487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani    public void releaseResources() {
651da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    }
652da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
653da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    private byte[] getOrCreateStatusBuffer() {
654da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        if (mStatusBuf == null) {
655da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            mStatusBuf = new byte[MAX_STATUS];
656da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        }
657da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        return mStatusBuf;
658da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    }
659da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
660da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    private void writeCommStatusAndClose(int status, String msg) {
661da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        if (mCommFd == null) {
662da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            // Not reliable, or someone already sent status
663da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            if (msg != null) {
664da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                Log.w(TAG, "Unable to inform peer: " + msg);
665da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            }
666da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            return;
667da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        }
668da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
669da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        if (status == Status.DETACHED) {
670da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            Log.w(TAG, "Peer expected signal when closed; unable to deliver after detach");
671da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        }
672da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
673da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        try {
674d99f9caba6600f1b5e0bc8a21681162ae42d6518Jeff Sharkey            if (status == Status.SILENCE) return;
675d99f9caba6600f1b5e0bc8a21681162ae42d6518Jeff Sharkey
676d99f9caba6600f1b5e0bc8a21681162ae42d6518Jeff Sharkey            // Since we're about to close, read off any remote status. It's
677d99f9caba6600f1b5e0bc8a21681162ae42d6518Jeff Sharkey            // okay to remember missing here.
678d99f9caba6600f1b5e0bc8a21681162ae42d6518Jeff Sharkey            mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer());
679da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
680d99f9caba6600f1b5e0bc8a21681162ae42d6518Jeff Sharkey            // Skip writing status when other end has already gone away.
681d99f9caba6600f1b5e0bc8a21681162ae42d6518Jeff Sharkey            if (mStatus != null) return;
682d99f9caba6600f1b5e0bc8a21681162ae42d6518Jeff Sharkey
683d99f9caba6600f1b5e0bc8a21681162ae42d6518Jeff Sharkey            try {
684d99f9caba6600f1b5e0bc8a21681162ae42d6518Jeff Sharkey                final byte[] buf = getOrCreateStatusBuffer();
685d99f9caba6600f1b5e0bc8a21681162ae42d6518Jeff Sharkey                int writePtr = 0;
686da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
687d99f9caba6600f1b5e0bc8a21681162ae42d6518Jeff Sharkey                Memory.pokeInt(buf, writePtr, status, ByteOrder.BIG_ENDIAN);
688d99f9caba6600f1b5e0bc8a21681162ae42d6518Jeff Sharkey                writePtr += 4;
689da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
690d99f9caba6600f1b5e0bc8a21681162ae42d6518Jeff Sharkey                if (msg != null) {
691d99f9caba6600f1b5e0bc8a21681162ae42d6518Jeff Sharkey                    final byte[] rawMsg = msg.getBytes();
692d99f9caba6600f1b5e0bc8a21681162ae42d6518Jeff Sharkey                    final int len = Math.min(rawMsg.length, buf.length - writePtr);
693d99f9caba6600f1b5e0bc8a21681162ae42d6518Jeff Sharkey                    System.arraycopy(rawMsg, 0, buf, writePtr, len);
694d99f9caba6600f1b5e0bc8a21681162ae42d6518Jeff Sharkey                    writePtr += len;
695da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                }
696d99f9caba6600f1b5e0bc8a21681162ae42d6518Jeff Sharkey
697d99f9caba6600f1b5e0bc8a21681162ae42d6518Jeff Sharkey                Libcore.os.write(mCommFd, buf, 0, writePtr);
698da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            } catch (ErrnoException e) {
699da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                // Reporting status is best-effort
700da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                Log.w(TAG, "Failed to report status: " + e);
701da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            }
702da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
703da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        } finally {
704da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            IoUtils.closeQuietly(mCommFd);
705da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            mCommFd = null;
706da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        }
707da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    }
708da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
709da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    private static Status readCommStatus(FileDescriptor comm, byte[] buf) {
710da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        try {
711da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            final int n = Libcore.os.read(comm, buf, 0, buf.length);
712da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            if (n == 0) {
713da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                // EOF means they're dead
714da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                return new Status(Status.DEAD);
715da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            } else {
716da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                final int status = Memory.peekInt(buf, 0, ByteOrder.BIG_ENDIAN);
717da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                if (status == Status.ERROR) {
718da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                    final String msg = new String(buf, 4, n - 4);
719da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                    return new Status(status, msg);
720da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                }
721da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                return new Status(status);
722da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            }
723da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        } catch (ErrnoException e) {
724da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            if (e.errno == OsConstants.EAGAIN) {
725da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                // Remote is still alive, but no status written yet
726da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                return null;
727da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            } else {
728da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                Log.d(TAG, "Failed to read status; assuming dead: " + e);
729da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                return new Status(Status.DEAD);
730da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            }
731da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        }
732da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    }
733da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
734da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    /**
735da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * Indicates if this ParcelFileDescriptor can communicate and detect remote
736da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * errors/crashes.
737da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     *
738b433bb8c96f98d280f4a8508ba500bd8f196a773Amith Yamasani     * @see #checkError()
739da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     */
740da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    public boolean canDetectErrors() {
741da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        if (mWrapped != null) {
742da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            return mWrapped.canDetectErrors();
743da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        } else {
744da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            return mCommFd != null;
745da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        }
746da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    }
747da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
748da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    /**
749da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * Detect and throw if the other end of a pipe or socket pair encountered an
750da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * error or crashed. This allows a reader to distinguish between a valid EOF
751da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * and an error/crash.
752da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * <p>
753da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * If this ParcelFileDescriptor is unable to detect remote errors, it will
754da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * return silently.
755da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     *
756b433bb8c96f98d280f4a8508ba500bd8f196a773Amith Yamasani     * @throws IOException for normal errors.
757b433bb8c96f98d280f4a8508ba500bd8f196a773Amith Yamasani     * @throws FileDescriptorDetachedException
758b433bb8c96f98d280f4a8508ba500bd8f196a773Amith Yamasani     *            if the remote side called {@link #detachFd()}. Once detached, the remote
759da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     *            side is unable to communicate any errors through
760b433bb8c96f98d280f4a8508ba500bd8f196a773Amith Yamasani     *            {@link #closeWithError(String)}.
761da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * @see #canDetectErrors()
762da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     */
763b433bb8c96f98d280f4a8508ba500bd8f196a773Amith Yamasani    public void checkError() throws IOException {
764da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        if (mWrapped != null) {
765b433bb8c96f98d280f4a8508ba500bd8f196a773Amith Yamasani            mWrapped.checkError();
766da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        } else {
767da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            if (mStatus == null) {
768da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                if (mCommFd == null) {
769da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                    Log.w(TAG, "Peer didn't provide a comm channel; unable to check for errors");
770da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                    return;
771da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                }
772da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
773da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                // Try reading status; it might be null if nothing written yet.
774da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                // Either way, we keep comm open to write our status later.
775da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer());
776da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            }
777da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
778b433bb8c96f98d280f4a8508ba500bd8f196a773Amith Yamasani            if (mStatus == null || mStatus.status == Status.OK) {
779da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                // No status yet, or everything is peachy!
780da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                return;
781da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            } else {
782da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                throw mStatus.asIOException();
783da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            }
7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7864390758f277645de6e81f6482d582473383cc917Elliott Hughes
7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * An InputStream you can create on a ParcelFileDescriptor, which will
7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * take care of calling {@link ParcelFileDescriptor#close
790fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate     * ParcelFileDescriptor.close()} for you when the stream is closed.
7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static class AutoCloseInputStream extends FileInputStream {
793da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        private final ParcelFileDescriptor mPfd;
7944390758f277645de6e81f6482d582473383cc917Elliott Hughes
795da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        public AutoCloseInputStream(ParcelFileDescriptor pfd) {
796da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            super(pfd.getFileDescriptor());
797da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            mPfd = pfd;
7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void close() throws IOException {
802fd9ddd1a40efc801dc7512950cb9336967b6f775Brian Carlstrom            try {
803da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                mPfd.close();
804fd9ddd1a40efc801dc7512950cb9336967b6f775Brian Carlstrom            } finally {
805fd9ddd1a40efc801dc7512950cb9336967b6f775Brian Carlstrom                super.close();
806fd9ddd1a40efc801dc7512950cb9336967b6f775Brian Carlstrom            }
8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8094390758f277645de6e81f6482d582473383cc917Elliott Hughes
8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * An OutputStream you can create on a ParcelFileDescriptor, which will
8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * take care of calling {@link ParcelFileDescriptor#close
813fa9e7c05c7be6891a6cf85a11dc635a6e6853078Christopher Tate     * ParcelFileDescriptor.close()} for you when the stream is closed.
8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static class AutoCloseOutputStream extends FileOutputStream {
816da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        private final ParcelFileDescriptor mPfd;
8174390758f277645de6e81f6482d582473383cc917Elliott Hughes
818da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        public AutoCloseOutputStream(ParcelFileDescriptor pfd) {
819da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            super(pfd.getFileDescriptor());
820da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            mPfd = pfd;
8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void close() throws IOException {
825fd9ddd1a40efc801dc7512950cb9336967b6f775Brian Carlstrom            try {
826da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                mPfd.close();
827fd9ddd1a40efc801dc7512950cb9336967b6f775Brian Carlstrom            } finally {
828fd9ddd1a40efc801dc7512950cb9336967b6f775Brian Carlstrom                super.close();
829fd9ddd1a40efc801dc7512950cb9336967b6f775Brian Carlstrom            }
8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8324390758f277645de6e81f6482d582473383cc917Elliott Hughes
8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public String toString() {
835da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        if (mWrapped != null) {
836da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            return mWrapped.toString();
837da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        } else {
838da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            return "{ParcelFileDescriptor: " + mFd + "}";
839da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        }
8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8414390758f277645de6e81f6482d582473383cc917Elliott Hughes
8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void finalize() throws Throwable {
844487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani        if (mWrapped != null) {
845487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani            releaseResources();
846487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani        }
8477407c948cbe7305c63ca33c471cf9e2a78674368Jeff Sharkey        if (mGuard != null) {
8487407c948cbe7305c63ca33c471cf9e2a78674368Jeff Sharkey            mGuard.warnIfOpen();
8497407c948cbe7305c63ca33c471cf9e2a78674368Jeff Sharkey        }
8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!mClosed) {
852da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                closeWithStatus(Status.LEAKED, null);
8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super.finalize();
8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8584390758f277645de6e81f6482d582473383cc917Elliott Hughes
8597407c948cbe7305c63ca33c471cf9e2a78674368Jeff Sharkey    @Override
8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int describeContents() {
861da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        if (mWrapped != null) {
862da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            return mWrapped.describeContents();
863da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        } else {
864da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            return Parcelable.CONTENTS_FILE_DESCRIPTOR;
865da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        }
8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
868b3e4ef37021a9e5518fdbc7d0cbb0a1709d5301bDan Egnor    /**
869b3e4ef37021a9e5518fdbc7d0cbb0a1709d5301bDan Egnor     * {@inheritDoc}
870b3e4ef37021a9e5518fdbc7d0cbb0a1709d5301bDan Egnor     * If {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set in flags,
871b3e4ef37021a9e5518fdbc7d0cbb0a1709d5301bDan Egnor     * the file descriptor will be closed after a copy is written to the Parcel.
872b3e4ef37021a9e5518fdbc7d0cbb0a1709d5301bDan Egnor     */
8737407c948cbe7305c63ca33c471cf9e2a78674368Jeff Sharkey    @Override
8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void writeToParcel(Parcel out, int flags) {
875da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        if (mWrapped != null) {
876487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani            try {
877487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani                mWrapped.writeToParcel(out, flags);
878487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani            } finally {
879487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani                releaseResources();
880487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani            }
881da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        } else {
882da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            out.writeFileDescriptor(mFd);
883da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            if (mCommFd != null) {
884da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                out.writeInt(1);
885da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                out.writeFileDescriptor(mCommFd);
886da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            } else {
887da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                out.writeInt(0);
888da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            }
889da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            if ((flags & PARCELABLE_WRITE_RETURN_VALUE) != 0 && !mClosed) {
890487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani                // Not a real close, so emit no status
891487c11a3101c6cd9fc18758b3032383666f55e46Amith Yamasani                closeWithStatus(Status.SILENCE, null);
8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final Parcelable.Creator<ParcelFileDescriptor> CREATOR
8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            = new Parcelable.Creator<ParcelFileDescriptor>() {
8987407c948cbe7305c63ca33c471cf9e2a78674368Jeff Sharkey        @Override
8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public ParcelFileDescriptor createFromParcel(Parcel in) {
900da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            final FileDescriptor fd = in.readRawFileDescriptor();
901da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            FileDescriptor commChannel = null;
902da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            if (in.readInt() != 0) {
903da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                commChannel = in.readRawFileDescriptor();
904da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            }
905da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            return new ParcelFileDescriptor(fd, commChannel);
9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9077407c948cbe7305c63ca33c471cf9e2a78674368Jeff Sharkey
9087407c948cbe7305c63ca33c471cf9e2a78674368Jeff Sharkey        @Override
9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public ParcelFileDescriptor[] newArray(int size) {
9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return new ParcelFileDescriptor[size];
9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
913da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
914da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    /**
915da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * Callback indicating that a ParcelFileDescriptor has been closed.
916da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     */
917da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    public interface OnCloseListener {
918da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        /**
919da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey         * Event indicating the ParcelFileDescriptor to which this listener was
920da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey         * attached has been closed.
921da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey         *
922da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey         * @param e error state, or {@code null} if closed cleanly.
923b433bb8c96f98d280f4a8508ba500bd8f196a773Amith Yamasani         *        If the close event was the result of
924b433bb8c96f98d280f4a8508ba500bd8f196a773Amith Yamasani         *        {@link ParcelFileDescriptor#detachFd()}, this will be a
925b433bb8c96f98d280f4a8508ba500bd8f196a773Amith Yamasani         *        {@link FileDescriptorDetachedException}. After detach the
926b433bb8c96f98d280f4a8508ba500bd8f196a773Amith Yamasani         *        remote side may continue reading/writing to the underlying
927b433bb8c96f98d280f4a8508ba500bd8f196a773Amith Yamasani         *        {@link FileDescriptor}, but they can no longer deliver
928b433bb8c96f98d280f4a8508ba500bd8f196a773Amith Yamasani         *        reliable close/error events.
929da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey         */
930b433bb8c96f98d280f4a8508ba500bd8f196a773Amith Yamasani        public void onClose(IOException e);
931b433bb8c96f98d280f4a8508ba500bd8f196a773Amith Yamasani    }
932b433bb8c96f98d280f4a8508ba500bd8f196a773Amith Yamasani
933b433bb8c96f98d280f4a8508ba500bd8f196a773Amith Yamasani    /**
934b433bb8c96f98d280f4a8508ba500bd8f196a773Amith Yamasani     * Exception that indicates that the file descriptor was detached.
935b433bb8c96f98d280f4a8508ba500bd8f196a773Amith Yamasani     */
936b433bb8c96f98d280f4a8508ba500bd8f196a773Amith Yamasani    public static class FileDescriptorDetachedException extends IOException {
937b433bb8c96f98d280f4a8508ba500bd8f196a773Amith Yamasani
938b433bb8c96f98d280f4a8508ba500bd8f196a773Amith Yamasani        private static final long serialVersionUID = 0xDe7ac4edFdL;
939b433bb8c96f98d280f4a8508ba500bd8f196a773Amith Yamasani
940b433bb8c96f98d280f4a8508ba500bd8f196a773Amith Yamasani        public FileDescriptorDetachedException() {
941b433bb8c96f98d280f4a8508ba500bd8f196a773Amith Yamasani            super("Remote side is detached");
942b433bb8c96f98d280f4a8508ba500bd8f196a773Amith Yamasani        }
943da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    }
944da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
945da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    /**
946da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * Internal class representing a remote status read by
947da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * {@link ParcelFileDescriptor#readCommStatus(FileDescriptor, byte[])}.
948da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     */
949da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    private static class Status {
950da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        /** Special value indicating remote side died. */
951da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        public static final int DEAD = -2;
952da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        /** Special value indicating no status should be written. */
953da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        public static final int SILENCE = -1;
954da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
955da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        /** Remote reported that everything went better than expected. */
956da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        public static final int OK = 0;
957da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        /** Remote reported error; length and message follow. */
958da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        public static final int ERROR = 1;
959da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        /** Remote reported {@link #detachFd()} and went rogue. */
960da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        public static final int DETACHED = 2;
961da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        /** Remote reported their object was finalized. */
962da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        public static final int LEAKED = 3;
963da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
964da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        public final int status;
965da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        public final String msg;
966da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
967da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        public Status(int status) {
968da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            this(status, null);
969da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        }
970da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
971da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        public Status(int status, String msg) {
972da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            this.status = status;
973da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            this.msg = msg;
974da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        }
975da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
976da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        public IOException asIOException() {
977da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            switch (status) {
978da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                case DEAD:
979da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                    return new IOException("Remote side is dead");
980da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                case OK:
981da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                    return null;
982da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                case ERROR:
983da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                    return new IOException("Remote error: " + msg);
984da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                case DETACHED:
985b433bb8c96f98d280f4a8508ba500bd8f196a773Amith Yamasani                    return new FileDescriptorDetachedException();
986da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                case LEAKED:
987da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                    return new IOException("Remote side was leaked");
988da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                default:
989da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                    return new IOException("Unknown status: " + status);
990da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            }
991da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        }
992da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    }
993da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
994da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    /**
995da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * Bridge to watch for remote status, and deliver to listener. Currently
996da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     * requires that communication socket is <em>blocking</em>.
997da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey     */
998da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    private static final class ListenerBridge extends Thread {
999da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        // TODO: switch to using Looper to avoid burning a thread
1000da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
1001da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        private FileDescriptor mCommFd;
1002da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        private final Handler mHandler;
1003da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
1004da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        public ListenerBridge(FileDescriptor comm, Looper looper, final OnCloseListener listener) {
1005da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            mCommFd = comm;
1006da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            mHandler = new Handler(looper) {
1007da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                @Override
1008da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                public void handleMessage(Message msg) {
1009da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                    final Status s = (Status) msg.obj;
1010b433bb8c96f98d280f4a8508ba500bd8f196a773Amith Yamasani                    listener.onClose(s != null ? s.asIOException() : null);
1011da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                }
1012da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            };
1013da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        }
1014da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey
1015da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        @Override
1016da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        public void run() {
1017da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            try {
1018da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                final byte[] buf = new byte[MAX_STATUS];
1019da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                final Status status = readCommStatus(mCommFd, buf);
1020da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                mHandler.obtainMessage(0, status).sendToTarget();
1021da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            } finally {
1022da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                IoUtils.closeQuietly(mCommFd);
1023da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey                mCommFd = null;
1024da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey            }
1025da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey        }
1026da5a3e12f4f8f965c57d6f93c74190f43ea233f3Jeff Sharkey    }
10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1028