blob: 7702c174ba2f03177f3ced0169f36063a80d8570 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.os;
Jeff Sharkey7407c942012-11-12 13:42:49 -080018
Elliott Hughes34385d32014-04-28 11:11:32 -070019import static android.system.OsConstants.AF_UNIX;
20import static android.system.OsConstants.SEEK_SET;
21import static android.system.OsConstants.SOCK_STREAM;
Jeff Brown6fd9f9a2015-03-12 19:45:47 -070022import static android.system.OsConstants.SOCK_SEQPACKET;
Elliott Hughes34385d32014-04-28 11:11:32 -070023import static android.system.OsConstants.S_ISLNK;
24import static android.system.OsConstants.S_ISREG;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070025
26import android.content.BroadcastReceiver;
27import android.content.ContentProvider;
Jeff Brown3f640522015-05-15 12:26:15 -070028import android.os.MessageQueue.OnFileDescriptorEventListener;
Elliott Hughes34385d32014-04-28 11:11:32 -070029import android.system.ErrnoException;
30import android.system.Os;
31import android.system.OsConstants;
32import android.system.StructStat;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070033import android.util.Log;
34
Jeff Sharkey7407c942012-11-12 13:42:49 -080035import dalvik.system.CloseGuard;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070036import libcore.io.IoUtils;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070037import libcore.io.Memory;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070038
Jeff Sharkeye861b422012-03-01 20:59:22 -080039import java.io.Closeable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import java.io.File;
41import java.io.FileDescriptor;
42import java.io.FileInputStream;
43import java.io.FileNotFoundException;
44import java.io.FileOutputStream;
45import java.io.IOException;
Neil Fuller43582df2014-04-11 17:29:54 +010046import java.io.InterruptedIOException;
Chia-chi Yeh47f8f0f2011-05-12 16:23:44 -070047import java.net.DatagramSocket;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import java.net.Socket;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070049import java.nio.ByteOrder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050
51/**
52 * The FileDescriptor returned by {@link Parcel#readFileDescriptor}, allowing
53 * you to close it when done with it.
54 */
Jeff Sharkeye861b422012-03-01 20:59:22 -080055public class ParcelFileDescriptor implements Parcelable, Closeable {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070056 private static final String TAG = "ParcelFileDescriptor";
57
58 private final FileDescriptor mFd;
59
60 /**
61 * Optional socket used to communicate close events, status at close, and
62 * detect remote process crashes.
63 */
64 private FileDescriptor mCommFd;
Jeff Sharkey7407c942012-11-12 13:42:49 -080065
66 /**
67 * Wrapped {@link ParcelFileDescriptor}, if any. Used to avoid
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070068 * double-closing {@link #mFd}.
Jeff Sharkey7407c942012-11-12 13:42:49 -080069 */
70 private final ParcelFileDescriptor mWrapped;
71
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070072 /**
73 * Maximum {@link #mStatusBuf} size; longer status messages will be
74 * truncated.
75 */
76 private static final int MAX_STATUS = 1024;
77
78 /**
79 * Temporary buffer used by {@link #readCommStatus(FileDescriptor, byte[])},
80 * allocated on-demand.
81 */
82 private byte[] mStatusBuf;
83
84 /**
Amith Yamasanib433bb82013-09-18 15:10:16 -070085 * Status read by {@link #checkError()}, or null if not read yet.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070086 */
87 private Status mStatus;
88
Jeff Sharkey7407c942012-11-12 13:42:49 -080089 private volatile boolean mClosed;
90
91 private final CloseGuard mGuard = CloseGuard.get();
Elliott Hughes43907582011-04-12 14:25:23 -070092
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093 /**
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070094 * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied and
95 * this file doesn't already exist, then create the file with permissions
96 * such that any application can read it.
97 *
98 * @deprecated Creating world-readable files is very dangerous, and likely
99 * to cause security holes in applications. It is strongly
100 * discouraged; instead, applications should use more formal
101 * mechanism for interactions such as {@link ContentProvider},
102 * {@link BroadcastReceiver}, and {@link android.app.Service}.
103 * There are no guarantees that this access mode will remain on
104 * a file, such as when it goes through a backup and restore.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105 */
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700106 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 public static final int MODE_WORLD_READABLE = 0x00000001;
Elliott Hughes43907582011-04-12 14:25:23 -0700108
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109 /**
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700110 * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied and
111 * this file doesn't already exist, then create the file with permissions
112 * such that any application can write it.
113 *
114 * @deprecated Creating world-writable files is very dangerous, and likely
115 * to cause security holes in applications. It is strongly
116 * discouraged; instead, applications should use more formal
117 * mechanism for interactions such as {@link ContentProvider},
118 * {@link BroadcastReceiver}, and {@link android.app.Service}.
119 * There are no guarantees that this access mode will remain on
120 * a file, such as when it goes through a backup and restore.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121 */
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700122 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123 public static final int MODE_WORLD_WRITEABLE = 0x00000002;
Elliott Hughes43907582011-04-12 14:25:23 -0700124
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125 /**
126 * For use with {@link #open}: open the file with read-only access.
127 */
128 public static final int MODE_READ_ONLY = 0x10000000;
Elliott Hughes43907582011-04-12 14:25:23 -0700129
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130 /**
131 * For use with {@link #open}: open the file with write-only access.
132 */
133 public static final int MODE_WRITE_ONLY = 0x20000000;
Elliott Hughes43907582011-04-12 14:25:23 -0700134
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 /**
136 * For use with {@link #open}: open the file with read and write access.
137 */
138 public static final int MODE_READ_WRITE = 0x30000000;
Elliott Hughes43907582011-04-12 14:25:23 -0700139
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 /**
141 * For use with {@link #open}: create the file if it doesn't already exist.
142 */
143 public static final int MODE_CREATE = 0x08000000;
Elliott Hughes43907582011-04-12 14:25:23 -0700144
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145 /**
146 * For use with {@link #open}: erase contents of file when opening.
147 */
148 public static final int MODE_TRUNCATE = 0x04000000;
Elliott Hughes43907582011-04-12 14:25:23 -0700149
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150 /**
151 * For use with {@link #open}: append to end of file while writing.
152 */
153 public static final int MODE_APPEND = 0x02000000;
Elliott Hughes43907582011-04-12 14:25:23 -0700154
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155 /**
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700156 * Create a new ParcelFileDescriptor wrapped around another descriptor. By
157 * default all method calls are delegated to the wrapped descriptor.
158 */
159 public ParcelFileDescriptor(ParcelFileDescriptor wrapped) {
160 // We keep a strong reference to the wrapped PFD, and rely on its
161 // finalizer to trigger CloseGuard. All calls are delegated to wrapper.
162 mWrapped = wrapped;
163 mFd = null;
164 mCommFd = null;
165 mClosed = true;
166 }
167
168 /** {@hide} */
169 public ParcelFileDescriptor(FileDescriptor fd) {
170 this(fd, null);
171 }
172
173 /** {@hide} */
174 public ParcelFileDescriptor(FileDescriptor fd, FileDescriptor commChannel) {
175 if (fd == null) {
176 throw new NullPointerException("FileDescriptor must not be null");
177 }
178 mWrapped = null;
179 mFd = fd;
180 mCommFd = commChannel;
181 mGuard.open("close");
182 }
183
184 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185 * Create a new ParcelFileDescriptor accessing a given file.
Elliott Hughes43907582011-04-12 14:25:23 -0700186 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187 * @param file The file to be opened.
188 * @param mode The desired access mode, must be one of
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700189 * {@link #MODE_READ_ONLY}, {@link #MODE_WRITE_ONLY}, or
190 * {@link #MODE_READ_WRITE}; may also be any combination of
191 * {@link #MODE_CREATE}, {@link #MODE_TRUNCATE},
192 * {@link #MODE_WORLD_READABLE}, and
193 * {@link #MODE_WORLD_WRITEABLE}.
194 * @return a new ParcelFileDescriptor pointing to the given file.
195 * @throws FileNotFoundException if the given file does not exist or can not
196 * be opened with the requested mode.
Jeff Sharkeye8c00d82013-10-15 15:46:10 -0700197 * @see #parseMode(String)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198 */
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700199 public static ParcelFileDescriptor open(File file, int mode) throws FileNotFoundException {
200 final FileDescriptor fd = openInternal(file, mode);
201 if (fd == null) return null;
Elliott Hughes43907582011-04-12 14:25:23 -0700202
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700203 return new ParcelFileDescriptor(fd);
204 }
205
206 /**
207 * Create a new ParcelFileDescriptor accessing a given file.
208 *
209 * @param file The file to be opened.
210 * @param mode The desired access mode, must be one of
211 * {@link #MODE_READ_ONLY}, {@link #MODE_WRITE_ONLY}, or
212 * {@link #MODE_READ_WRITE}; may also be any combination of
213 * {@link #MODE_CREATE}, {@link #MODE_TRUNCATE},
214 * {@link #MODE_WORLD_READABLE}, and
215 * {@link #MODE_WORLD_WRITEABLE}.
216 * @param handler to call listener from; must not be null.
217 * @param listener to be invoked when the returned descriptor has been
218 * closed; must not be null.
219 * @return a new ParcelFileDescriptor pointing to the given file.
220 * @throws FileNotFoundException if the given file does not exist or can not
221 * be opened with the requested mode.
Jeff Sharkeye8c00d82013-10-15 15:46:10 -0700222 * @see #parseMode(String)
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700223 */
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700224 public static ParcelFileDescriptor open(File file, int mode, Handler handler,
225 final OnCloseListener listener) throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700226 if (handler == null) {
227 throw new IllegalArgumentException("Handler must not be null");
228 }
229 if (listener == null) {
230 throw new IllegalArgumentException("Listener must not be null");
231 }
232
233 final FileDescriptor fd = openInternal(file, mode);
234 if (fd == null) return null;
235
Daichi Hirono91e3b502015-12-16 09:24:16 +0900236 return fromFd(fd, handler, listener);
237 }
238
239 /** {@hide} */
240 public static ParcelFileDescriptor fromFd(
241 FileDescriptor fd, Handler handler, final OnCloseListener listener) throws IOException {
242 if (handler == null) {
243 throw new IllegalArgumentException("Handler must not be null");
244 }
245 if (listener == null) {
246 throw new IllegalArgumentException("Listener must not be null");
247 }
248
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700249 final FileDescriptor[] comm = createCommSocketPair();
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700250 final ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd, comm[0]);
Jeff Brownb2a19852015-03-12 19:49:25 -0700251 final MessageQueue queue = handler.getLooper().getQueue();
Jeff Brown3f640522015-05-15 12:26:15 -0700252 queue.addOnFileDescriptorEventListener(comm[1],
253 OnFileDescriptorEventListener.EVENT_INPUT, new OnFileDescriptorEventListener() {
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700254 @Override
255 public int onFileDescriptorEvents(FileDescriptor fd, int events) {
256 Status status = null;
Jeff Brown3f640522015-05-15 12:26:15 -0700257 if ((events & OnFileDescriptorEventListener.EVENT_INPUT) != 0) {
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700258 final byte[] buf = new byte[MAX_STATUS];
259 status = readCommStatus(fd, buf);
Jeff Brown3f640522015-05-15 12:26:15 -0700260 } else if ((events & OnFileDescriptorEventListener.EVENT_ERROR) != 0) {
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700261 status = new Status(Status.DEAD);
262 }
263 if (status != null) {
Jeff Brown3f640522015-05-15 12:26:15 -0700264 queue.removeOnFileDescriptorEventListener(fd);
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700265 IoUtils.closeQuietly(fd);
266 listener.onClose(status.asIOException());
Jeff Brownb2a19852015-03-12 19:49:25 -0700267 return 0;
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700268 }
269 return EVENT_INPUT;
270 }
271 });
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700272
273 return pfd;
274 }
275
276 private static FileDescriptor openInternal(File file, int mode) throws FileNotFoundException {
277 if ((mode & MODE_READ_WRITE) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800278 throw new IllegalArgumentException(
279 "Must specify MODE_READ_ONLY, MODE_WRITE_ONLY, or MODE_READ_WRITE");
280 }
Elliott Hughes43907582011-04-12 14:25:23 -0700281
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700282 final String path = file.getPath();
283 return Parcel.openFileDescriptor(path, mode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284 }
285
286 /**
Dianne Hackborne17aeb32011-04-07 15:11:57 -0700287 * Create a new ParcelFileDescriptor that is a dup of an existing
288 * FileDescriptor. This obeys standard POSIX semantics, where the
289 * new file descriptor shared state such as file position with the
290 * original file descriptor.
291 */
292 public static ParcelFileDescriptor dup(FileDescriptor orig) throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700293 try {
Elliott Hughes34385d32014-04-28 11:11:32 -0700294 final FileDescriptor fd = Os.dup(orig);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700295 return new ParcelFileDescriptor(fd);
296 } catch (ErrnoException e) {
297 throw e.rethrowAsIOException();
298 }
Dianne Hackborne17aeb32011-04-07 15:11:57 -0700299 }
300
301 /**
Dianne Hackborn62f20ec2011-08-15 17:40:28 -0700302 * Create a new ParcelFileDescriptor that is a dup of the existing
303 * FileDescriptor. This obeys standard POSIX semantics, where the
304 * new file descriptor shared state such as file position with the
305 * original file descriptor.
306 */
307 public ParcelFileDescriptor dup() throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700308 if (mWrapped != null) {
309 return mWrapped.dup();
310 } else {
311 return dup(getFileDescriptor());
312 }
Dianne Hackborn62f20ec2011-08-15 17:40:28 -0700313 }
314
315 /**
Dianne Hackbornea2117bd2011-05-20 10:37:34 -0700316 * Create a new ParcelFileDescriptor from a raw native fd. The new
317 * ParcelFileDescriptor holds a dup of the original fd passed in here,
318 * so you must still close that fd as well as the new ParcelFileDescriptor.
319 *
320 * @param fd The native fd that the ParcelFileDescriptor should dup.
321 *
322 * @return Returns a new ParcelFileDescriptor holding a FileDescriptor
323 * for a dup of the given fd.
324 */
325 public static ParcelFileDescriptor fromFd(int fd) throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700326 final FileDescriptor original = new FileDescriptor();
327 original.setInt$(fd);
Dianne Hackbornea2117bd2011-05-20 10:37:34 -0700328
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700329 try {
Elliott Hughes34385d32014-04-28 11:11:32 -0700330 final FileDescriptor dup = Os.dup(original);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700331 return new ParcelFileDescriptor(dup);
332 } catch (ErrnoException e) {
333 throw e.rethrowAsIOException();
334 }
335 }
Dianne Hackbornea2117bd2011-05-20 10:37:34 -0700336
337 /**
338 * Take ownership of a raw native fd in to a new ParcelFileDescriptor.
339 * The returned ParcelFileDescriptor now owns the given fd, and will be
340 * responsible for closing it. You must not close the fd yourself.
341 *
342 * @param fd The native fd that the ParcelFileDescriptor should adopt.
343 *
344 * @return Returns a new ParcelFileDescriptor holding a FileDescriptor
345 * for the given fd.
346 */
347 public static ParcelFileDescriptor adoptFd(int fd) {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700348 final FileDescriptor fdesc = new FileDescriptor();
349 fdesc.setInt$(fd);
350
Dianne Hackbornea2117bd2011-05-20 10:37:34 -0700351 return new ParcelFileDescriptor(fdesc);
352 }
353
Dianne Hackbornea2117bd2011-05-20 10:37:34 -0700354 /**
355 * Create a new ParcelFileDescriptor from the specified Socket. The new
356 * ParcelFileDescriptor holds a dup of the original FileDescriptor in
357 * the Socket, so you must still close the Socket as well as the new
358 * ParcelFileDescriptor.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 *
360 * @param socket The Socket whose FileDescriptor is used to create
361 * a new ParcelFileDescriptor.
362 *
363 * @return A new ParcelFileDescriptor with the FileDescriptor of the
364 * specified Socket.
365 */
366 public static ParcelFileDescriptor fromSocket(Socket socket) {
Elliott Hughes43907582011-04-12 14:25:23 -0700367 FileDescriptor fd = socket.getFileDescriptor$();
Dianne Hackborn18668392010-03-23 22:10:55 -0700368 return fd != null ? new ParcelFileDescriptor(fd) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800369 }
370
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371 /**
Chia-chi Yeh47f8f0f2011-05-12 16:23:44 -0700372 * Create a new ParcelFileDescriptor from the specified DatagramSocket.
373 *
374 * @param datagramSocket The DatagramSocket whose FileDescriptor is used
375 * to create a new ParcelFileDescriptor.
376 *
377 * @return A new ParcelFileDescriptor with the FileDescriptor of the
378 * specified DatagramSocket.
379 */
380 public static ParcelFileDescriptor fromDatagramSocket(DatagramSocket datagramSocket) {
381 FileDescriptor fd = datagramSocket.getFileDescriptor$();
382 return fd != null ? new ParcelFileDescriptor(fd) : null;
383 }
384
385 /**
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700386 * Create two ParcelFileDescriptors structured as a data pipe. The first
387 * ParcelFileDescriptor in the returned array is the read side; the second
388 * is the write side.
389 */
390 public static ParcelFileDescriptor[] createPipe() throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700391 try {
Elliott Hughes34385d32014-04-28 11:11:32 -0700392 final FileDescriptor[] fds = Os.pipe();
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700393 return new ParcelFileDescriptor[] {
394 new ParcelFileDescriptor(fds[0]),
395 new ParcelFileDescriptor(fds[1]) };
396 } catch (ErrnoException e) {
397 throw e.rethrowAsIOException();
398 }
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700399 }
400
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700401 /**
402 * Create two ParcelFileDescriptors structured as a data pipe. The first
403 * ParcelFileDescriptor in the returned array is the read side; the second
404 * is the write side.
405 * <p>
406 * The write end has the ability to deliver an error message through
407 * {@link #closeWithError(String)} which can be handled by the read end
Amith Yamasanib433bb82013-09-18 15:10:16 -0700408 * calling {@link #checkError()}, usually after detecting an EOF.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700409 * This can also be used to detect remote crashes.
410 */
411 public static ParcelFileDescriptor[] createReliablePipe() throws IOException {
412 try {
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700413 final FileDescriptor[] comm = createCommSocketPair();
Elliott Hughes34385d32014-04-28 11:11:32 -0700414 final FileDescriptor[] fds = Os.pipe();
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700415 return new ParcelFileDescriptor[] {
416 new ParcelFileDescriptor(fds[0], comm[0]),
417 new ParcelFileDescriptor(fds[1], comm[1]) };
418 } catch (ErrnoException e) {
419 throw e.rethrowAsIOException();
420 }
421 }
422
423 /**
424 * Create two ParcelFileDescriptors structured as a pair of sockets
425 * connected to each other. The two sockets are indistinguishable.
426 */
427 public static ParcelFileDescriptor[] createSocketPair() throws IOException {
Mike Lockwoodced0c252014-11-20 12:22:30 -0800428 return createSocketPair(SOCK_STREAM);
429 }
430
431 /**
432 * @hide
433 */
434 public static ParcelFileDescriptor[] createSocketPair(int type) throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700435 try {
436 final FileDescriptor fd0 = new FileDescriptor();
437 final FileDescriptor fd1 = new FileDescriptor();
Mike Lockwoodced0c252014-11-20 12:22:30 -0800438 Os.socketpair(AF_UNIX, type, 0, fd0, fd1);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700439 return new ParcelFileDescriptor[] {
440 new ParcelFileDescriptor(fd0),
441 new ParcelFileDescriptor(fd1) };
442 } catch (ErrnoException e) {
443 throw e.rethrowAsIOException();
444 }
445 }
446
447 /**
448 * Create two ParcelFileDescriptors structured as a pair of sockets
449 * connected to each other. The two sockets are indistinguishable.
450 * <p>
451 * Both ends have the ability to deliver an error message through
452 * {@link #closeWithError(String)} which can be detected by the other end
Amith Yamasanib433bb82013-09-18 15:10:16 -0700453 * calling {@link #checkError()}, usually after detecting an EOF.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700454 * This can also be used to detect remote crashes.
455 */
456 public static ParcelFileDescriptor[] createReliableSocketPair() throws IOException {
Mike Lockwoodced0c252014-11-20 12:22:30 -0800457 return createReliableSocketPair(SOCK_STREAM);
458 }
459
460 /**
461 * @hide
462 */
463 public static ParcelFileDescriptor[] createReliableSocketPair(int type) throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700464 try {
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700465 final FileDescriptor[] comm = createCommSocketPair();
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700466 final FileDescriptor fd0 = new FileDescriptor();
467 final FileDescriptor fd1 = new FileDescriptor();
Mike Lockwoodced0c252014-11-20 12:22:30 -0800468 Os.socketpair(AF_UNIX, type, 0, fd0, fd1);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700469 return new ParcelFileDescriptor[] {
470 new ParcelFileDescriptor(fd0, comm[0]),
471 new ParcelFileDescriptor(fd1, comm[1]) };
472 } catch (ErrnoException e) {
473 throw e.rethrowAsIOException();
474 }
475 }
476
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700477 private static FileDescriptor[] createCommSocketPair() throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700478 try {
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700479 // Use SOCK_SEQPACKET so that we have a guarantee that the status
480 // is written and read atomically as one unit and is not split
481 // across multiple IO operations.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700482 final FileDescriptor comm1 = new FileDescriptor();
483 final FileDescriptor comm2 = new FileDescriptor();
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700484 Os.socketpair(AF_UNIX, SOCK_SEQPACKET, 0, comm1, comm2);
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700485 IoUtils.setBlocking(comm1, false);
486 IoUtils.setBlocking(comm2, false);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700487 return new FileDescriptor[] { comm1, comm2 };
488 } catch (ErrnoException e) {
489 throw e.rethrowAsIOException();
490 }
491 }
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700492
493 /**
Dianne Hackborn540f86a2011-01-11 17:52:22 -0800494 * @hide Please use createPipe() or ContentProvider.openPipeHelper().
Bjorn Bringerta006b4722010-04-14 14:43:26 +0100495 * Gets a file descriptor for a read-only copy of the given data.
496 *
497 * @param data Data to copy.
498 * @param name Name for the shared memory area that may back the file descriptor.
499 * This is purely informative and may be {@code null}.
500 * @return A ParcelFileDescriptor.
501 * @throws IOException if there is an error while creating the shared memory area.
502 */
Dianne Hackborna2ea7472010-12-20 12:10:01 -0800503 @Deprecated
Bjorn Bringerta006b4722010-04-14 14:43:26 +0100504 public static ParcelFileDescriptor fromData(byte[] data, String name) throws IOException {
505 if (data == null) return null;
506 MemoryFile file = new MemoryFile(name, data.length);
507 if (data.length > 0) {
508 file.writeBytes(data, 0, 0, data.length);
509 }
510 file.deactivate();
511 FileDescriptor fd = file.getFileDescriptor();
512 return fd != null ? new ParcelFileDescriptor(fd) : null;
513 }
514
515 /**
Adam Lesinskieb8c3f92013-09-20 14:08:25 -0700516 * Converts a string representing a file mode, such as "rw", into a bitmask suitable for use
517 * with {@link #open}.
518 * <p>
519 * @param mode The string representation of the file mode.
520 * @return A bitmask representing the given file mode.
521 * @throws IllegalArgumentException if the given string does not match a known file mode.
522 */
523 public static int parseMode(String mode) {
524 final int modeBits;
525 if ("r".equals(mode)) {
526 modeBits = ParcelFileDescriptor.MODE_READ_ONLY;
527 } else if ("w".equals(mode) || "wt".equals(mode)) {
528 modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
529 | ParcelFileDescriptor.MODE_CREATE
530 | ParcelFileDescriptor.MODE_TRUNCATE;
531 } else if ("wa".equals(mode)) {
532 modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
533 | ParcelFileDescriptor.MODE_CREATE
534 | ParcelFileDescriptor.MODE_APPEND;
535 } else if ("rw".equals(mode)) {
536 modeBits = ParcelFileDescriptor.MODE_READ_WRITE
537 | ParcelFileDescriptor.MODE_CREATE;
538 } else if ("rwt".equals(mode)) {
539 modeBits = ParcelFileDescriptor.MODE_READ_WRITE
540 | ParcelFileDescriptor.MODE_CREATE
541 | ParcelFileDescriptor.MODE_TRUNCATE;
542 } else {
543 throw new IllegalArgumentException("Bad mode '" + mode + "'");
544 }
545 return modeBits;
546 }
547
548 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800549 * Retrieve the actual FileDescriptor associated with this object.
Elliott Hughes43907582011-04-12 14:25:23 -0700550 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551 * @return Returns the FileDescriptor associated with this object.
552 */
553 public FileDescriptor getFileDescriptor() {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700554 if (mWrapped != null) {
555 return mWrapped.getFileDescriptor();
556 } else {
557 return mFd;
558 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800559 }
Elliott Hughes43907582011-04-12 14:25:23 -0700560
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800561 /**
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700562 * Return the total size of the file representing this fd, as determined by
563 * {@code stat()}. Returns -1 if the fd is not a file.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800564 */
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700565 public long getStatSize() {
566 if (mWrapped != null) {
567 return mWrapped.getStatSize();
568 } else {
569 try {
Elliott Hughes34385d32014-04-28 11:11:32 -0700570 final StructStat st = Os.fstat(mFd);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700571 if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
572 return st.st_size;
573 } else {
574 return -1;
575 }
576 } catch (ErrnoException e) {
577 Log.w(TAG, "fstat() failed: " + e);
578 return -1;
579 }
580 }
581 }
Elliott Hughes43907582011-04-12 14:25:23 -0700582
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583 /**
584 * This is needed for implementing AssetFileDescriptor.AutoCloseOutputStream,
585 * and I really don't think we want it to be public.
586 * @hide
587 */
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700588 public long seekTo(long pos) throws IOException {
589 if (mWrapped != null) {
590 return mWrapped.seekTo(pos);
591 } else {
592 try {
Elliott Hughes34385d32014-04-28 11:11:32 -0700593 return Os.lseek(mFd, pos, SEEK_SET);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700594 } catch (ErrnoException e) {
595 throw e.rethrowAsIOException();
596 }
597 }
598 }
Elliott Hughes43907582011-04-12 14:25:23 -0700599
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800600 /**
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800601 * Return the native fd int for this ParcelFileDescriptor. The
602 * ParcelFileDescriptor still owns the fd, and it still must be closed
603 * through this API.
604 */
605 public int getFd() {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700606 if (mWrapped != null) {
607 return mWrapped.getFd();
608 } else {
609 if (mClosed) {
610 throw new IllegalStateException("Already closed");
611 }
612 return mFd.getInt$();
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800613 }
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800614 }
Elliott Hughes43907582011-04-12 14:25:23 -0700615
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800616 /**
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700617 * Return the native fd int for this ParcelFileDescriptor and detach it from
618 * the object here. You are now responsible for closing the fd in native
619 * code.
620 * <p>
621 * You should not detach when the original creator of the descriptor is
622 * expecting a reliable signal through {@link #close()} or
623 * {@link #closeWithError(String)}.
624 *
625 * @see #canDetectErrors()
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800626 */
627 public int detachFd() {
Jeff Sharkey7407c942012-11-12 13:42:49 -0800628 if (mWrapped != null) {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700629 return mWrapped.detachFd();
630 } else {
631 if (mClosed) {
632 throw new IllegalStateException("Already closed");
633 }
634 final int fd = getFd();
635 Parcel.clearFileDescriptor(mFd);
636 writeCommStatusAndClose(Status.DETACHED, null);
Makoto Onukib30ad6f2015-06-11 12:34:22 -0700637 mClosed = true;
638 mGuard.close();
639 releaseResources();
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800640 return fd;
641 }
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800642 }
Elliott Hughes43907582011-04-12 14:25:23 -0700643
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800644 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800645 * Close the ParcelFileDescriptor. This implementation closes the underlying
646 * OS resources allocated to represent this stream.
Elliott Hughes43907582011-04-12 14:25:23 -0700647 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800648 * @throws IOException
649 * If an error occurs attempting to close this ParcelFileDescriptor.
650 */
Jeff Sharkey7407c942012-11-12 13:42:49 -0800651 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800652 public void close() throws IOException {
Jeff Sharkey7407c942012-11-12 13:42:49 -0800653 if (mWrapped != null) {
Amith Yamasani487c11a2013-09-18 09:16:15 -0700654 try {
655 mWrapped.close();
656 } finally {
657 releaseResources();
658 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800659 } else {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700660 closeWithStatus(Status.OK, null);
661 }
662 }
663
664 /**
665 * Close the ParcelFileDescriptor, informing any peer that an error occurred
666 * while processing. If the creator of this descriptor is not observing
667 * errors, it will close normally.
668 *
669 * @param msg describing the error; must not be null.
670 */
671 public void closeWithError(String msg) throws IOException {
672 if (mWrapped != null) {
Amith Yamasani487c11a2013-09-18 09:16:15 -0700673 try {
674 mWrapped.closeWithError(msg);
675 } finally {
676 releaseResources();
677 }
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700678 } else {
679 if (msg == null) {
680 throw new IllegalArgumentException("Message must not be null");
681 }
682 closeWithStatus(Status.ERROR, msg);
683 }
684 }
685
Amith Yamasani487c11a2013-09-18 09:16:15 -0700686 private void closeWithStatus(int status, String msg) {
687 if (mClosed) return;
688 mClosed = true;
689 mGuard.close();
690 // Status MUST be sent before closing actual descriptor
691 writeCommStatusAndClose(status, msg);
692 IoUtils.closeQuietly(mFd);
693 releaseResources();
694 }
695
696 /**
697 * Called when the fd is being closed, for subclasses to release any other resources
698 * associated with it, such as acquired providers.
699 * @hide
700 */
701 public void releaseResources() {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700702 }
703
704 private byte[] getOrCreateStatusBuffer() {
705 if (mStatusBuf == null) {
706 mStatusBuf = new byte[MAX_STATUS];
707 }
708 return mStatusBuf;
709 }
710
711 private void writeCommStatusAndClose(int status, String msg) {
712 if (mCommFd == null) {
713 // Not reliable, or someone already sent status
714 if (msg != null) {
715 Log.w(TAG, "Unable to inform peer: " + msg);
716 }
717 return;
718 }
719
720 if (status == Status.DETACHED) {
721 Log.w(TAG, "Peer expected signal when closed; unable to deliver after detach");
722 }
723
724 try {
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700725 if (status == Status.SILENCE) return;
726
727 // Since we're about to close, read off any remote status. It's
728 // okay to remember missing here.
729 mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer());
730
731 // Skip writing status when other end has already gone away.
732 if (mStatus != null) return;
733
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700734 try {
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700735 final byte[] buf = getOrCreateStatusBuffer();
736 int writePtr = 0;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700737
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700738 Memory.pokeInt(buf, writePtr, status, ByteOrder.BIG_ENDIAN);
739 writePtr += 4;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700740
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700741 if (msg != null) {
742 final byte[] rawMsg = msg.getBytes();
743 final int len = Math.min(rawMsg.length, buf.length - writePtr);
744 System.arraycopy(rawMsg, 0, buf, writePtr, len);
745 writePtr += len;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700746 }
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700747
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700748 // Must write the entire status as a single operation.
Elliott Hughes34385d32014-04-28 11:11:32 -0700749 Os.write(mCommFd, buf, 0, writePtr);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700750 } catch (ErrnoException e) {
751 // Reporting status is best-effort
752 Log.w(TAG, "Failed to report status: " + e);
Neil Fuller43582df2014-04-11 17:29:54 +0100753 } catch (InterruptedIOException e) {
754 // Reporting status is best-effort
755 Log.w(TAG, "Failed to report status: " + e);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700756 }
757
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700758 } finally {
759 IoUtils.closeQuietly(mCommFd);
760 mCommFd = null;
761 }
762 }
763
764 private static Status readCommStatus(FileDescriptor comm, byte[] buf) {
765 try {
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700766 // Must read the entire status as a single operation.
Elliott Hughes34385d32014-04-28 11:11:32 -0700767 final int n = Os.read(comm, buf, 0, buf.length);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700768 if (n == 0) {
769 // EOF means they're dead
770 return new Status(Status.DEAD);
771 } else {
772 final int status = Memory.peekInt(buf, 0, ByteOrder.BIG_ENDIAN);
773 if (status == Status.ERROR) {
774 final String msg = new String(buf, 4, n - 4);
775 return new Status(status, msg);
776 }
777 return new Status(status);
778 }
779 } catch (ErrnoException e) {
780 if (e.errno == OsConstants.EAGAIN) {
781 // Remote is still alive, but no status written yet
782 return null;
783 } else {
784 Log.d(TAG, "Failed to read status; assuming dead: " + e);
785 return new Status(Status.DEAD);
786 }
Neil Fuller43582df2014-04-11 17:29:54 +0100787 } catch (InterruptedIOException e) {
788 Log.d(TAG, "Failed to read status; assuming dead: " + e);
789 return new Status(Status.DEAD);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700790 }
791 }
792
793 /**
794 * Indicates if this ParcelFileDescriptor can communicate and detect remote
795 * errors/crashes.
796 *
Amith Yamasanib433bb82013-09-18 15:10:16 -0700797 * @see #checkError()
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700798 */
799 public boolean canDetectErrors() {
800 if (mWrapped != null) {
801 return mWrapped.canDetectErrors();
802 } else {
803 return mCommFd != null;
804 }
805 }
806
807 /**
808 * Detect and throw if the other end of a pipe or socket pair encountered an
809 * error or crashed. This allows a reader to distinguish between a valid EOF
810 * and an error/crash.
811 * <p>
812 * If this ParcelFileDescriptor is unable to detect remote errors, it will
813 * return silently.
814 *
Amith Yamasanib433bb82013-09-18 15:10:16 -0700815 * @throws IOException for normal errors.
816 * @throws FileDescriptorDetachedException
817 * if the remote side called {@link #detachFd()}. Once detached, the remote
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700818 * side is unable to communicate any errors through
Amith Yamasanib433bb82013-09-18 15:10:16 -0700819 * {@link #closeWithError(String)}.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700820 * @see #canDetectErrors()
821 */
Amith Yamasanib433bb82013-09-18 15:10:16 -0700822 public void checkError() throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700823 if (mWrapped != null) {
Amith Yamasanib433bb82013-09-18 15:10:16 -0700824 mWrapped.checkError();
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700825 } else {
826 if (mStatus == null) {
827 if (mCommFd == null) {
828 Log.w(TAG, "Peer didn't provide a comm channel; unable to check for errors");
829 return;
830 }
831
832 // Try reading status; it might be null if nothing written yet.
833 // Either way, we keep comm open to write our status later.
834 mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer());
835 }
836
Amith Yamasanib433bb82013-09-18 15:10:16 -0700837 if (mStatus == null || mStatus.status == Status.OK) {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700838 // No status yet, or everything is peachy!
839 return;
840 } else {
841 throw mStatus.asIOException();
842 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800843 }
844 }
Elliott Hughes43907582011-04-12 14:25:23 -0700845
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800846 /**
847 * An InputStream you can create on a ParcelFileDescriptor, which will
848 * take care of calling {@link ParcelFileDescriptor#close
Christopher Tatefa9e7c02010-05-06 12:07:10 -0700849 * ParcelFileDescriptor.close()} for you when the stream is closed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800850 */
851 public static class AutoCloseInputStream extends FileInputStream {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700852 private final ParcelFileDescriptor mPfd;
Elliott Hughes43907582011-04-12 14:25:23 -0700853
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700854 public AutoCloseInputStream(ParcelFileDescriptor pfd) {
855 super(pfd.getFileDescriptor());
856 mPfd = pfd;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800857 }
858
859 @Override
860 public void close() throws IOException {
Brian Carlstromfd9ddd12010-11-04 11:24:58 -0700861 try {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700862 mPfd.close();
Brian Carlstromfd9ddd12010-11-04 11:24:58 -0700863 } finally {
864 super.close();
865 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800866 }
Tomasz Mikolajewskiad3b6162016-05-30 10:17:08 +0900867
868 @Override
869 public int read() throws IOException {
870 final int result = super.read();
871 if (result == -1 && mPfd.canDetectErrors()) {
872 // Check for errors only on EOF, to minimize overhead.
873 mPfd.checkError();
874 }
875 return result;
876 }
877
878 @Override
879 public int read(byte[] b) throws IOException {
880 final int result = super.read(b);
881 if (result == -1 && mPfd.canDetectErrors()) {
882 mPfd.checkError();
883 }
884 return result;
885 }
886
887 @Override
888 public int read(byte[] b, int off, int len) throws IOException {
889 final int result = super.read(b, off, len);
890 if (result == -1 && mPfd.canDetectErrors()) {
891 mPfd.checkError();
892 }
893 return result;
894 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800895 }
Elliott Hughes43907582011-04-12 14:25:23 -0700896
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800897 /**
898 * An OutputStream you can create on a ParcelFileDescriptor, which will
899 * take care of calling {@link ParcelFileDescriptor#close
Christopher Tatefa9e7c02010-05-06 12:07:10 -0700900 * ParcelFileDescriptor.close()} for you when the stream is closed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800901 */
902 public static class AutoCloseOutputStream extends FileOutputStream {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700903 private final ParcelFileDescriptor mPfd;
Elliott Hughes43907582011-04-12 14:25:23 -0700904
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700905 public AutoCloseOutputStream(ParcelFileDescriptor pfd) {
906 super(pfd.getFileDescriptor());
907 mPfd = pfd;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800908 }
909
910 @Override
911 public void close() throws IOException {
Brian Carlstromfd9ddd12010-11-04 11:24:58 -0700912 try {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700913 mPfd.close();
Brian Carlstromfd9ddd12010-11-04 11:24:58 -0700914 } finally {
915 super.close();
916 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800917 }
918 }
Elliott Hughes43907582011-04-12 14:25:23 -0700919
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800920 @Override
921 public String toString() {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700922 if (mWrapped != null) {
923 return mWrapped.toString();
924 } else {
925 return "{ParcelFileDescriptor: " + mFd + "}";
926 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800927 }
Elliott Hughes43907582011-04-12 14:25:23 -0700928
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800929 @Override
930 protected void finalize() throws Throwable {
Amith Yamasani487c11a2013-09-18 09:16:15 -0700931 if (mWrapped != null) {
932 releaseResources();
933 }
Jeff Sharkey7407c942012-11-12 13:42:49 -0800934 if (mGuard != null) {
935 mGuard.warnIfOpen();
936 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800937 try {
938 if (!mClosed) {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700939 closeWithStatus(Status.LEAKED, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800940 }
941 } finally {
942 super.finalize();
943 }
944 }
Elliott Hughes43907582011-04-12 14:25:23 -0700945
Jeff Sharkey7407c942012-11-12 13:42:49 -0800946 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800947 public int describeContents() {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700948 if (mWrapped != null) {
949 return mWrapped.describeContents();
950 } else {
951 return Parcelable.CONTENTS_FILE_DESCRIPTOR;
952 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 }
954
Dan Egnorb3e4ef32010-07-20 09:03:35 -0700955 /**
956 * {@inheritDoc}
957 * If {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set in flags,
958 * the file descriptor will be closed after a copy is written to the Parcel.
959 */
Jeff Sharkey7407c942012-11-12 13:42:49 -0800960 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800961 public void writeToParcel(Parcel out, int flags) {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700962 if (mWrapped != null) {
Amith Yamasani487c11a2013-09-18 09:16:15 -0700963 try {
964 mWrapped.writeToParcel(out, flags);
965 } finally {
966 releaseResources();
967 }
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700968 } else {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700969 if (mCommFd != null) {
970 out.writeInt(1);
Tim Kilbourn4bf27b52015-06-02 15:57:45 -0700971 out.writeFileDescriptor(mFd);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700972 out.writeFileDescriptor(mCommFd);
973 } else {
974 out.writeInt(0);
Tim Kilbourn4bf27b52015-06-02 15:57:45 -0700975 out.writeFileDescriptor(mFd);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700976 }
977 if ((flags & PARCELABLE_WRITE_RETURN_VALUE) != 0 && !mClosed) {
Amith Yamasani487c11a2013-09-18 09:16:15 -0700978 // Not a real close, so emit no status
979 closeWithStatus(Status.SILENCE, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800980 }
981 }
982 }
983
984 public static final Parcelable.Creator<ParcelFileDescriptor> CREATOR
985 = new Parcelable.Creator<ParcelFileDescriptor>() {
Jeff Sharkey7407c942012-11-12 13:42:49 -0800986 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800987 public ParcelFileDescriptor createFromParcel(Parcel in) {
Tim Kilbourn4bf27b52015-06-02 15:57:45 -0700988 int hasCommChannel = in.readInt();
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700989 final FileDescriptor fd = in.readRawFileDescriptor();
990 FileDescriptor commChannel = null;
Tim Kilbourn4bf27b52015-06-02 15:57:45 -0700991 if (hasCommChannel != 0) {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700992 commChannel = in.readRawFileDescriptor();
993 }
994 return new ParcelFileDescriptor(fd, commChannel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800995 }
Jeff Sharkey7407c942012-11-12 13:42:49 -0800996
997 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998 public ParcelFileDescriptor[] newArray(int size) {
999 return new ParcelFileDescriptor[size];
1000 }
1001 };
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001002
1003 /**
1004 * Callback indicating that a ParcelFileDescriptor has been closed.
1005 */
1006 public interface OnCloseListener {
1007 /**
1008 * Event indicating the ParcelFileDescriptor to which this listener was
1009 * attached has been closed.
1010 *
1011 * @param e error state, or {@code null} if closed cleanly.
Amith Yamasanib433bb82013-09-18 15:10:16 -07001012 * If the close event was the result of
1013 * {@link ParcelFileDescriptor#detachFd()}, this will be a
1014 * {@link FileDescriptorDetachedException}. After detach the
1015 * remote side may continue reading/writing to the underlying
1016 * {@link FileDescriptor}, but they can no longer deliver
1017 * reliable close/error events.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001018 */
Amith Yamasanib433bb82013-09-18 15:10:16 -07001019 public void onClose(IOException e);
1020 }
1021
1022 /**
1023 * Exception that indicates that the file descriptor was detached.
1024 */
1025 public static class FileDescriptorDetachedException extends IOException {
1026
1027 private static final long serialVersionUID = 0xDe7ac4edFdL;
1028
1029 public FileDescriptorDetachedException() {
1030 super("Remote side is detached");
1031 }
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001032 }
1033
1034 /**
1035 * Internal class representing a remote status read by
1036 * {@link ParcelFileDescriptor#readCommStatus(FileDescriptor, byte[])}.
1037 */
1038 private static class Status {
1039 /** Special value indicating remote side died. */
1040 public static final int DEAD = -2;
1041 /** Special value indicating no status should be written. */
1042 public static final int SILENCE = -1;
1043
1044 /** Remote reported that everything went better than expected. */
1045 public static final int OK = 0;
1046 /** Remote reported error; length and message follow. */
1047 public static final int ERROR = 1;
1048 /** Remote reported {@link #detachFd()} and went rogue. */
1049 public static final int DETACHED = 2;
1050 /** Remote reported their object was finalized. */
1051 public static final int LEAKED = 3;
1052
1053 public final int status;
1054 public final String msg;
1055
1056 public Status(int status) {
1057 this(status, null);
1058 }
1059
1060 public Status(int status, String msg) {
1061 this.status = status;
1062 this.msg = msg;
1063 }
1064
1065 public IOException asIOException() {
1066 switch (status) {
1067 case DEAD:
1068 return new IOException("Remote side is dead");
1069 case OK:
1070 return null;
1071 case ERROR:
1072 return new IOException("Remote error: " + msg);
1073 case DETACHED:
Amith Yamasanib433bb82013-09-18 15:10:16 -07001074 return new FileDescriptorDetachedException();
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001075 case LEAKED:
1076 return new IOException("Remote side was leaked");
1077 default:
1078 return new IOException("Unknown status: " + status);
1079 }
1080 }
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001081
1082 @Override
Jeff Brown6fd9f9a2015-03-12 19:45:47 -07001083 public String toString() {
1084 return "{" + status + ": " + msg + "}";
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001085 }
1086 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001087}