blob: 24bf05ef671dbbfbc69c7531f631765021bddac3 [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
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070019import static libcore.io.OsConstants.AF_UNIX;
20import static libcore.io.OsConstants.SEEK_SET;
21import static libcore.io.OsConstants.SOCK_STREAM;
22import static libcore.io.OsConstants.S_ISLNK;
23import static libcore.io.OsConstants.S_ISREG;
24
25import android.content.BroadcastReceiver;
26import android.content.ContentProvider;
27import android.util.Log;
28
Jeff Sharkey7407c942012-11-12 13:42:49 -080029import dalvik.system.CloseGuard;
30
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070031import libcore.io.ErrnoException;
32import libcore.io.IoUtils;
33import libcore.io.Libcore;
34import libcore.io.Memory;
35import libcore.io.OsConstants;
36import libcore.io.StructStat;
37
Jeff Sharkeye861b422012-03-01 20:59:22 -080038import java.io.Closeable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import java.io.File;
40import java.io.FileDescriptor;
41import java.io.FileInputStream;
42import java.io.FileNotFoundException;
43import java.io.FileOutputStream;
44import java.io.IOException;
Neil Fuller43582df2014-04-11 17:29:54 +010045import java.io.InterruptedIOException;
Chia-chi Yeh47f8f0f2011-05-12 16:23:44 -070046import java.net.DatagramSocket;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import java.net.Socket;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070048import java.nio.ByteOrder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049
50/**
51 * The FileDescriptor returned by {@link Parcel#readFileDescriptor}, allowing
52 * you to close it when done with it.
53 */
Jeff Sharkeye861b422012-03-01 20:59:22 -080054public class ParcelFileDescriptor implements Parcelable, Closeable {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070055 private static final String TAG = "ParcelFileDescriptor";
56
57 private final FileDescriptor mFd;
58
59 /**
60 * Optional socket used to communicate close events, status at close, and
61 * detect remote process crashes.
62 */
63 private FileDescriptor mCommFd;
Jeff Sharkey7407c942012-11-12 13:42:49 -080064
65 /**
66 * Wrapped {@link ParcelFileDescriptor}, if any. Used to avoid
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070067 * double-closing {@link #mFd}.
Jeff Sharkey7407c942012-11-12 13:42:49 -080068 */
69 private final ParcelFileDescriptor mWrapped;
70
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070071 /**
72 * Maximum {@link #mStatusBuf} size; longer status messages will be
73 * truncated.
74 */
75 private static final int MAX_STATUS = 1024;
76
77 /**
78 * Temporary buffer used by {@link #readCommStatus(FileDescriptor, byte[])},
79 * allocated on-demand.
80 */
81 private byte[] mStatusBuf;
82
83 /**
Amith Yamasanib433bb82013-09-18 15:10:16 -070084 * Status read by {@link #checkError()}, or null if not read yet.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070085 */
86 private Status mStatus;
87
Jeff Sharkey7407c942012-11-12 13:42:49 -080088 private volatile boolean mClosed;
89
90 private final CloseGuard mGuard = CloseGuard.get();
Elliott Hughes43907582011-04-12 14:25:23 -070091
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 /**
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070093 * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied and
94 * this file doesn't already exist, then create the file with permissions
95 * such that any application can read it.
96 *
97 * @deprecated Creating world-readable files is very dangerous, and likely
98 * to cause security holes in applications. It is strongly
99 * discouraged; instead, applications should use more formal
100 * mechanism for interactions such as {@link ContentProvider},
101 * {@link BroadcastReceiver}, and {@link android.app.Service}.
102 * There are no guarantees that this access mode will remain on
103 * a file, such as when it goes through a backup and restore.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 */
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700105 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106 public static final int MODE_WORLD_READABLE = 0x00000001;
Elliott Hughes43907582011-04-12 14:25:23 -0700107
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108 /**
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700109 * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied and
110 * this file doesn't already exist, then create the file with permissions
111 * such that any application can write it.
112 *
113 * @deprecated Creating world-writable files is very dangerous, and likely
114 * to cause security holes in applications. It is strongly
115 * discouraged; instead, applications should use more formal
116 * mechanism for interactions such as {@link ContentProvider},
117 * {@link BroadcastReceiver}, and {@link android.app.Service}.
118 * There are no guarantees that this access mode will remain on
119 * a file, such as when it goes through a backup and restore.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800120 */
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700121 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122 public static final int MODE_WORLD_WRITEABLE = 0x00000002;
Elliott Hughes43907582011-04-12 14:25:23 -0700123
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124 /**
125 * For use with {@link #open}: open the file with read-only access.
126 */
127 public static final int MODE_READ_ONLY = 0x10000000;
Elliott Hughes43907582011-04-12 14:25:23 -0700128
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129 /**
130 * For use with {@link #open}: open the file with write-only access.
131 */
132 public static final int MODE_WRITE_ONLY = 0x20000000;
Elliott Hughes43907582011-04-12 14:25:23 -0700133
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134 /**
135 * For use with {@link #open}: open the file with read and write access.
136 */
137 public static final int MODE_READ_WRITE = 0x30000000;
Elliott Hughes43907582011-04-12 14:25:23 -0700138
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139 /**
140 * For use with {@link #open}: create the file if it doesn't already exist.
141 */
142 public static final int MODE_CREATE = 0x08000000;
Elliott Hughes43907582011-04-12 14:25:23 -0700143
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144 /**
145 * For use with {@link #open}: erase contents of file when opening.
146 */
147 public static final int MODE_TRUNCATE = 0x04000000;
Elliott Hughes43907582011-04-12 14:25:23 -0700148
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149 /**
150 * For use with {@link #open}: append to end of file while writing.
151 */
152 public static final int MODE_APPEND = 0x02000000;
Elliott Hughes43907582011-04-12 14:25:23 -0700153
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800154 /**
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700155 * Create a new ParcelFileDescriptor wrapped around another descriptor. By
156 * default all method calls are delegated to the wrapped descriptor.
157 */
158 public ParcelFileDescriptor(ParcelFileDescriptor wrapped) {
159 // We keep a strong reference to the wrapped PFD, and rely on its
160 // finalizer to trigger CloseGuard. All calls are delegated to wrapper.
161 mWrapped = wrapped;
162 mFd = null;
163 mCommFd = null;
164 mClosed = true;
165 }
166
167 /** {@hide} */
168 public ParcelFileDescriptor(FileDescriptor fd) {
169 this(fd, null);
170 }
171
172 /** {@hide} */
173 public ParcelFileDescriptor(FileDescriptor fd, FileDescriptor commChannel) {
174 if (fd == null) {
175 throw new NullPointerException("FileDescriptor must not be null");
176 }
177 mWrapped = null;
178 mFd = fd;
179 mCommFd = commChannel;
180 mGuard.open("close");
181 }
182
183 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800184 * Create a new ParcelFileDescriptor accessing a given file.
Elliott Hughes43907582011-04-12 14:25:23 -0700185 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800186 * @param file The file to be opened.
187 * @param mode The desired access mode, must be one of
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700188 * {@link #MODE_READ_ONLY}, {@link #MODE_WRITE_ONLY}, or
189 * {@link #MODE_READ_WRITE}; may also be any combination of
190 * {@link #MODE_CREATE}, {@link #MODE_TRUNCATE},
191 * {@link #MODE_WORLD_READABLE}, and
192 * {@link #MODE_WORLD_WRITEABLE}.
193 * @return a new ParcelFileDescriptor pointing to the given file.
194 * @throws FileNotFoundException if the given file does not exist or can not
195 * be opened with the requested mode.
Jeff Sharkeye8c00d82013-10-15 15:46:10 -0700196 * @see #parseMode(String)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197 */
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700198 public static ParcelFileDescriptor open(File file, int mode) throws FileNotFoundException {
199 final FileDescriptor fd = openInternal(file, mode);
200 if (fd == null) return null;
Elliott Hughes43907582011-04-12 14:25:23 -0700201
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700202 return new ParcelFileDescriptor(fd);
203 }
204
205 /**
206 * Create a new ParcelFileDescriptor accessing a given file.
207 *
208 * @param file The file to be opened.
209 * @param mode The desired access mode, must be one of
210 * {@link #MODE_READ_ONLY}, {@link #MODE_WRITE_ONLY}, or
211 * {@link #MODE_READ_WRITE}; may also be any combination of
212 * {@link #MODE_CREATE}, {@link #MODE_TRUNCATE},
213 * {@link #MODE_WORLD_READABLE}, and
214 * {@link #MODE_WORLD_WRITEABLE}.
215 * @param handler to call listener from; must not be null.
216 * @param listener to be invoked when the returned descriptor has been
217 * closed; must not be null.
218 * @return a new ParcelFileDescriptor pointing to the given file.
219 * @throws FileNotFoundException if the given file does not exist or can not
220 * be opened with the requested mode.
Jeff Sharkeye8c00d82013-10-15 15:46:10 -0700221 * @see #parseMode(String)
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700222 */
223 public static ParcelFileDescriptor open(
224 File file, int mode, Handler handler, OnCloseListener listener) throws IOException {
225 if (handler == null) {
226 throw new IllegalArgumentException("Handler must not be null");
227 }
228 if (listener == null) {
229 throw new IllegalArgumentException("Listener must not be null");
230 }
231
232 final FileDescriptor fd = openInternal(file, mode);
233 if (fd == null) return null;
234
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700235 final FileDescriptor[] comm = createCommSocketPair();
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700236 final ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd, comm[0]);
237
238 // Kick off thread to watch for status updates
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700239 IoUtils.setBlocking(comm[1], true);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700240 final ListenerBridge bridge = new ListenerBridge(comm[1], handler.getLooper(), listener);
241 bridge.start();
242
243 return pfd;
244 }
245
246 private static FileDescriptor openInternal(File file, int mode) throws FileNotFoundException {
247 if ((mode & MODE_READ_WRITE) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248 throw new IllegalArgumentException(
249 "Must specify MODE_READ_ONLY, MODE_WRITE_ONLY, or MODE_READ_WRITE");
250 }
Elliott Hughes43907582011-04-12 14:25:23 -0700251
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700252 final String path = file.getPath();
253 return Parcel.openFileDescriptor(path, mode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800254 }
255
256 /**
Dianne Hackborne17aeb32011-04-07 15:11:57 -0700257 * Create a new ParcelFileDescriptor that is a dup of an existing
258 * FileDescriptor. This obeys standard POSIX semantics, where the
259 * new file descriptor shared state such as file position with the
260 * original file descriptor.
261 */
262 public static ParcelFileDescriptor dup(FileDescriptor orig) throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700263 try {
264 final FileDescriptor fd = Libcore.os.dup(orig);
265 return new ParcelFileDescriptor(fd);
266 } catch (ErrnoException e) {
267 throw e.rethrowAsIOException();
268 }
Dianne Hackborne17aeb32011-04-07 15:11:57 -0700269 }
270
271 /**
Dianne Hackborn62f20ec2011-08-15 17:40:28 -0700272 * Create a new ParcelFileDescriptor that is a dup of the existing
273 * FileDescriptor. This obeys standard POSIX semantics, where the
274 * new file descriptor shared state such as file position with the
275 * original file descriptor.
276 */
277 public ParcelFileDescriptor dup() throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700278 if (mWrapped != null) {
279 return mWrapped.dup();
280 } else {
281 return dup(getFileDescriptor());
282 }
Dianne Hackborn62f20ec2011-08-15 17:40:28 -0700283 }
284
285 /**
Dianne Hackbornea2117bd2011-05-20 10:37:34 -0700286 * Create a new ParcelFileDescriptor from a raw native fd. The new
287 * ParcelFileDescriptor holds a dup of the original fd passed in here,
288 * so you must still close that fd as well as the new ParcelFileDescriptor.
289 *
290 * @param fd The native fd that the ParcelFileDescriptor should dup.
291 *
292 * @return Returns a new ParcelFileDescriptor holding a FileDescriptor
293 * for a dup of the given fd.
294 */
295 public static ParcelFileDescriptor fromFd(int fd) throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700296 final FileDescriptor original = new FileDescriptor();
297 original.setInt$(fd);
Dianne Hackbornea2117bd2011-05-20 10:37:34 -0700298
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700299 try {
300 final FileDescriptor dup = Libcore.os.dup(original);
301 return new ParcelFileDescriptor(dup);
302 } catch (ErrnoException e) {
303 throw e.rethrowAsIOException();
304 }
305 }
Dianne Hackbornea2117bd2011-05-20 10:37:34 -0700306
307 /**
308 * Take ownership of a raw native fd in to a new ParcelFileDescriptor.
309 * The returned ParcelFileDescriptor now owns the given fd, and will be
310 * responsible for closing it. You must not close the fd yourself.
311 *
312 * @param fd The native fd that the ParcelFileDescriptor should adopt.
313 *
314 * @return Returns a new ParcelFileDescriptor holding a FileDescriptor
315 * for the given fd.
316 */
317 public static ParcelFileDescriptor adoptFd(int fd) {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700318 final FileDescriptor fdesc = new FileDescriptor();
319 fdesc.setInt$(fd);
320
Dianne Hackbornea2117bd2011-05-20 10:37:34 -0700321 return new ParcelFileDescriptor(fdesc);
322 }
323
Dianne Hackbornea2117bd2011-05-20 10:37:34 -0700324 /**
325 * Create a new ParcelFileDescriptor from the specified Socket. The new
326 * ParcelFileDescriptor holds a dup of the original FileDescriptor in
327 * the Socket, so you must still close the Socket as well as the new
328 * ParcelFileDescriptor.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329 *
330 * @param socket The Socket whose FileDescriptor is used to create
331 * a new ParcelFileDescriptor.
332 *
333 * @return A new ParcelFileDescriptor with the FileDescriptor of the
334 * specified Socket.
335 */
336 public static ParcelFileDescriptor fromSocket(Socket socket) {
Elliott Hughes43907582011-04-12 14:25:23 -0700337 FileDescriptor fd = socket.getFileDescriptor$();
Dianne Hackborn18668392010-03-23 22:10:55 -0700338 return fd != null ? new ParcelFileDescriptor(fd) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339 }
340
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800341 /**
Chia-chi Yeh47f8f0f2011-05-12 16:23:44 -0700342 * Create a new ParcelFileDescriptor from the specified DatagramSocket.
343 *
344 * @param datagramSocket The DatagramSocket whose FileDescriptor is used
345 * to create a new ParcelFileDescriptor.
346 *
347 * @return A new ParcelFileDescriptor with the FileDescriptor of the
348 * specified DatagramSocket.
349 */
350 public static ParcelFileDescriptor fromDatagramSocket(DatagramSocket datagramSocket) {
351 FileDescriptor fd = datagramSocket.getFileDescriptor$();
352 return fd != null ? new ParcelFileDescriptor(fd) : null;
353 }
354
355 /**
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700356 * Create two ParcelFileDescriptors structured as a data pipe. The first
357 * ParcelFileDescriptor in the returned array is the read side; the second
358 * is the write side.
359 */
360 public static ParcelFileDescriptor[] createPipe() throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700361 try {
362 final FileDescriptor[] fds = Libcore.os.pipe();
363 return new ParcelFileDescriptor[] {
364 new ParcelFileDescriptor(fds[0]),
365 new ParcelFileDescriptor(fds[1]) };
366 } catch (ErrnoException e) {
367 throw e.rethrowAsIOException();
368 }
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700369 }
370
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700371 /**
372 * Create two ParcelFileDescriptors structured as a data pipe. The first
373 * ParcelFileDescriptor in the returned array is the read side; the second
374 * is the write side.
375 * <p>
376 * The write end has the ability to deliver an error message through
377 * {@link #closeWithError(String)} which can be handled by the read end
Amith Yamasanib433bb82013-09-18 15:10:16 -0700378 * calling {@link #checkError()}, usually after detecting an EOF.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700379 * This can also be used to detect remote crashes.
380 */
381 public static ParcelFileDescriptor[] createReliablePipe() throws IOException {
382 try {
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700383 final FileDescriptor[] comm = createCommSocketPair();
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700384 final FileDescriptor[] fds = Libcore.os.pipe();
385 return new ParcelFileDescriptor[] {
386 new ParcelFileDescriptor(fds[0], comm[0]),
387 new ParcelFileDescriptor(fds[1], comm[1]) };
388 } catch (ErrnoException e) {
389 throw e.rethrowAsIOException();
390 }
391 }
392
393 /**
394 * Create two ParcelFileDescriptors structured as a pair of sockets
395 * connected to each other. The two sockets are indistinguishable.
396 */
397 public static ParcelFileDescriptor[] createSocketPair() throws IOException {
398 try {
399 final FileDescriptor fd0 = new FileDescriptor();
400 final FileDescriptor fd1 = new FileDescriptor();
401 Libcore.os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd0, fd1);
402 return new ParcelFileDescriptor[] {
403 new ParcelFileDescriptor(fd0),
404 new ParcelFileDescriptor(fd1) };
405 } catch (ErrnoException e) {
406 throw e.rethrowAsIOException();
407 }
408 }
409
410 /**
411 * Create two ParcelFileDescriptors structured as a pair of sockets
412 * connected to each other. The two sockets are indistinguishable.
413 * <p>
414 * Both ends have the ability to deliver an error message through
415 * {@link #closeWithError(String)} which can be detected by the other end
Amith Yamasanib433bb82013-09-18 15:10:16 -0700416 * calling {@link #checkError()}, usually after detecting an EOF.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700417 * This can also be used to detect remote crashes.
418 */
419 public static ParcelFileDescriptor[] createReliableSocketPair() throws IOException {
420 try {
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700421 final FileDescriptor[] comm = createCommSocketPair();
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700422 final FileDescriptor fd0 = new FileDescriptor();
423 final FileDescriptor fd1 = new FileDescriptor();
424 Libcore.os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd0, fd1);
425 return new ParcelFileDescriptor[] {
426 new ParcelFileDescriptor(fd0, comm[0]),
427 new ParcelFileDescriptor(fd1, comm[1]) };
428 } catch (ErrnoException e) {
429 throw e.rethrowAsIOException();
430 }
431 }
432
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700433 private static FileDescriptor[] createCommSocketPair() throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700434 try {
435 final FileDescriptor comm1 = new FileDescriptor();
436 final FileDescriptor comm2 = new FileDescriptor();
437 Libcore.os.socketpair(AF_UNIX, SOCK_STREAM, 0, comm1, comm2);
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700438 IoUtils.setBlocking(comm1, false);
439 IoUtils.setBlocking(comm2, false);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700440 return new FileDescriptor[] { comm1, comm2 };
441 } catch (ErrnoException e) {
442 throw e.rethrowAsIOException();
443 }
444 }
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700445
446 /**
Dianne Hackborn540f86a2011-01-11 17:52:22 -0800447 * @hide Please use createPipe() or ContentProvider.openPipeHelper().
Bjorn Bringerta006b4722010-04-14 14:43:26 +0100448 * Gets a file descriptor for a read-only copy of the given data.
449 *
450 * @param data Data to copy.
451 * @param name Name for the shared memory area that may back the file descriptor.
452 * This is purely informative and may be {@code null}.
453 * @return A ParcelFileDescriptor.
454 * @throws IOException if there is an error while creating the shared memory area.
455 */
Dianne Hackborna2ea7472010-12-20 12:10:01 -0800456 @Deprecated
Bjorn Bringerta006b4722010-04-14 14:43:26 +0100457 public static ParcelFileDescriptor fromData(byte[] data, String name) throws IOException {
458 if (data == null) return null;
459 MemoryFile file = new MemoryFile(name, data.length);
460 if (data.length > 0) {
461 file.writeBytes(data, 0, 0, data.length);
462 }
463 file.deactivate();
464 FileDescriptor fd = file.getFileDescriptor();
465 return fd != null ? new ParcelFileDescriptor(fd) : null;
466 }
467
468 /**
Adam Lesinskieb8c3f92013-09-20 14:08:25 -0700469 * Converts a string representing a file mode, such as "rw", into a bitmask suitable for use
470 * with {@link #open}.
471 * <p>
472 * @param mode The string representation of the file mode.
473 * @return A bitmask representing the given file mode.
474 * @throws IllegalArgumentException if the given string does not match a known file mode.
475 */
476 public static int parseMode(String mode) {
477 final int modeBits;
478 if ("r".equals(mode)) {
479 modeBits = ParcelFileDescriptor.MODE_READ_ONLY;
480 } else if ("w".equals(mode) || "wt".equals(mode)) {
481 modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
482 | ParcelFileDescriptor.MODE_CREATE
483 | ParcelFileDescriptor.MODE_TRUNCATE;
484 } else if ("wa".equals(mode)) {
485 modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
486 | ParcelFileDescriptor.MODE_CREATE
487 | ParcelFileDescriptor.MODE_APPEND;
488 } else if ("rw".equals(mode)) {
489 modeBits = ParcelFileDescriptor.MODE_READ_WRITE
490 | ParcelFileDescriptor.MODE_CREATE;
491 } else if ("rwt".equals(mode)) {
492 modeBits = ParcelFileDescriptor.MODE_READ_WRITE
493 | ParcelFileDescriptor.MODE_CREATE
494 | ParcelFileDescriptor.MODE_TRUNCATE;
495 } else {
496 throw new IllegalArgumentException("Bad mode '" + mode + "'");
497 }
498 return modeBits;
499 }
500
501 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800502 * Retrieve the actual FileDescriptor associated with this object.
Elliott Hughes43907582011-04-12 14:25:23 -0700503 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504 * @return Returns the FileDescriptor associated with this object.
505 */
506 public FileDescriptor getFileDescriptor() {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700507 if (mWrapped != null) {
508 return mWrapped.getFileDescriptor();
509 } else {
510 return mFd;
511 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800512 }
Elliott Hughes43907582011-04-12 14:25:23 -0700513
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800514 /**
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700515 * Return the total size of the file representing this fd, as determined by
516 * {@code stat()}. Returns -1 if the fd is not a file.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800517 */
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700518 public long getStatSize() {
519 if (mWrapped != null) {
520 return mWrapped.getStatSize();
521 } else {
522 try {
523 final StructStat st = Libcore.os.fstat(mFd);
524 if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
525 return st.st_size;
526 } else {
527 return -1;
528 }
529 } catch (ErrnoException e) {
530 Log.w(TAG, "fstat() failed: " + e);
531 return -1;
532 }
533 }
534 }
Elliott Hughes43907582011-04-12 14:25:23 -0700535
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800536 /**
537 * This is needed for implementing AssetFileDescriptor.AutoCloseOutputStream,
538 * and I really don't think we want it to be public.
539 * @hide
540 */
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700541 public long seekTo(long pos) throws IOException {
542 if (mWrapped != null) {
543 return mWrapped.seekTo(pos);
544 } else {
545 try {
546 return Libcore.os.lseek(mFd, pos, SEEK_SET);
547 } catch (ErrnoException e) {
548 throw e.rethrowAsIOException();
549 }
550 }
551 }
Elliott Hughes43907582011-04-12 14:25:23 -0700552
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800553 /**
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800554 * Return the native fd int for this ParcelFileDescriptor. The
555 * ParcelFileDescriptor still owns the fd, and it still must be closed
556 * through this API.
557 */
558 public int getFd() {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700559 if (mWrapped != null) {
560 return mWrapped.getFd();
561 } else {
562 if (mClosed) {
563 throw new IllegalStateException("Already closed");
564 }
565 return mFd.getInt$();
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800566 }
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800567 }
Elliott Hughes43907582011-04-12 14:25:23 -0700568
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800569 /**
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700570 * Return the native fd int for this ParcelFileDescriptor and detach it from
571 * the object here. You are now responsible for closing the fd in native
572 * code.
573 * <p>
574 * You should not detach when the original creator of the descriptor is
575 * expecting a reliable signal through {@link #close()} or
576 * {@link #closeWithError(String)}.
577 *
578 * @see #canDetectErrors()
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800579 */
580 public int detachFd() {
Jeff Sharkey7407c942012-11-12 13:42:49 -0800581 if (mWrapped != null) {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700582 return mWrapped.detachFd();
583 } else {
584 if (mClosed) {
585 throw new IllegalStateException("Already closed");
586 }
587 final int fd = getFd();
588 Parcel.clearFileDescriptor(mFd);
589 writeCommStatusAndClose(Status.DETACHED, null);
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800590 return fd;
591 }
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800592 }
Elliott Hughes43907582011-04-12 14:25:23 -0700593
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800594 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800595 * Close the ParcelFileDescriptor. This implementation closes the underlying
596 * OS resources allocated to represent this stream.
Elliott Hughes43907582011-04-12 14:25:23 -0700597 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598 * @throws IOException
599 * If an error occurs attempting to close this ParcelFileDescriptor.
600 */
Jeff Sharkey7407c942012-11-12 13:42:49 -0800601 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800602 public void close() throws IOException {
Jeff Sharkey7407c942012-11-12 13:42:49 -0800603 if (mWrapped != null) {
Amith Yamasani487c11a2013-09-18 09:16:15 -0700604 try {
605 mWrapped.close();
606 } finally {
607 releaseResources();
608 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 } else {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700610 closeWithStatus(Status.OK, null);
611 }
612 }
613
614 /**
615 * Close the ParcelFileDescriptor, informing any peer that an error occurred
616 * while processing. If the creator of this descriptor is not observing
617 * errors, it will close normally.
618 *
619 * @param msg describing the error; must not be null.
620 */
621 public void closeWithError(String msg) throws IOException {
622 if (mWrapped != null) {
Amith Yamasani487c11a2013-09-18 09:16:15 -0700623 try {
624 mWrapped.closeWithError(msg);
625 } finally {
626 releaseResources();
627 }
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700628 } else {
629 if (msg == null) {
630 throw new IllegalArgumentException("Message must not be null");
631 }
632 closeWithStatus(Status.ERROR, msg);
633 }
634 }
635
Amith Yamasani487c11a2013-09-18 09:16:15 -0700636 private void closeWithStatus(int status, String msg) {
637 if (mClosed) return;
638 mClosed = true;
639 mGuard.close();
640 // Status MUST be sent before closing actual descriptor
641 writeCommStatusAndClose(status, msg);
642 IoUtils.closeQuietly(mFd);
643 releaseResources();
644 }
645
646 /**
647 * Called when the fd is being closed, for subclasses to release any other resources
648 * associated with it, such as acquired providers.
649 * @hide
650 */
651 public void releaseResources() {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700652 }
653
654 private byte[] getOrCreateStatusBuffer() {
655 if (mStatusBuf == null) {
656 mStatusBuf = new byte[MAX_STATUS];
657 }
658 return mStatusBuf;
659 }
660
661 private void writeCommStatusAndClose(int status, String msg) {
662 if (mCommFd == null) {
663 // Not reliable, or someone already sent status
664 if (msg != null) {
665 Log.w(TAG, "Unable to inform peer: " + msg);
666 }
667 return;
668 }
669
670 if (status == Status.DETACHED) {
671 Log.w(TAG, "Peer expected signal when closed; unable to deliver after detach");
672 }
673
674 try {
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700675 if (status == Status.SILENCE) return;
676
677 // Since we're about to close, read off any remote status. It's
678 // okay to remember missing here.
679 mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer());
680
681 // Skip writing status when other end has already gone away.
682 if (mStatus != null) return;
683
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700684 try {
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700685 final byte[] buf = getOrCreateStatusBuffer();
686 int writePtr = 0;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700687
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700688 Memory.pokeInt(buf, writePtr, status, ByteOrder.BIG_ENDIAN);
689 writePtr += 4;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700690
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700691 if (msg != null) {
692 final byte[] rawMsg = msg.getBytes();
693 final int len = Math.min(rawMsg.length, buf.length - writePtr);
694 System.arraycopy(rawMsg, 0, buf, writePtr, len);
695 writePtr += len;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700696 }
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700697
698 Libcore.os.write(mCommFd, buf, 0, writePtr);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700699 } catch (ErrnoException e) {
700 // Reporting status is best-effort
701 Log.w(TAG, "Failed to report status: " + e);
Neil Fuller43582df2014-04-11 17:29:54 +0100702 } catch (InterruptedIOException e) {
703 // Reporting status is best-effort
704 Log.w(TAG, "Failed to report status: " + e);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700705 }
706
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700707 } finally {
708 IoUtils.closeQuietly(mCommFd);
709 mCommFd = null;
710 }
711 }
712
713 private static Status readCommStatus(FileDescriptor comm, byte[] buf) {
714 try {
715 final int n = Libcore.os.read(comm, buf, 0, buf.length);
716 if (n == 0) {
717 // EOF means they're dead
718 return new Status(Status.DEAD);
719 } else {
720 final int status = Memory.peekInt(buf, 0, ByteOrder.BIG_ENDIAN);
721 if (status == Status.ERROR) {
722 final String msg = new String(buf, 4, n - 4);
723 return new Status(status, msg);
724 }
725 return new Status(status);
726 }
727 } catch (ErrnoException e) {
728 if (e.errno == OsConstants.EAGAIN) {
729 // Remote is still alive, but no status written yet
730 return null;
731 } else {
732 Log.d(TAG, "Failed to read status; assuming dead: " + e);
733 return new Status(Status.DEAD);
734 }
Neil Fuller43582df2014-04-11 17:29:54 +0100735 } catch (InterruptedIOException e) {
736 Log.d(TAG, "Failed to read status; assuming dead: " + e);
737 return new Status(Status.DEAD);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700738 }
739 }
740
741 /**
742 * Indicates if this ParcelFileDescriptor can communicate and detect remote
743 * errors/crashes.
744 *
Amith Yamasanib433bb82013-09-18 15:10:16 -0700745 * @see #checkError()
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700746 */
747 public boolean canDetectErrors() {
748 if (mWrapped != null) {
749 return mWrapped.canDetectErrors();
750 } else {
751 return mCommFd != null;
752 }
753 }
754
755 /**
756 * Detect and throw if the other end of a pipe or socket pair encountered an
757 * error or crashed. This allows a reader to distinguish between a valid EOF
758 * and an error/crash.
759 * <p>
760 * If this ParcelFileDescriptor is unable to detect remote errors, it will
761 * return silently.
762 *
Amith Yamasanib433bb82013-09-18 15:10:16 -0700763 * @throws IOException for normal errors.
764 * @throws FileDescriptorDetachedException
765 * if the remote side called {@link #detachFd()}. Once detached, the remote
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700766 * side is unable to communicate any errors through
Amith Yamasanib433bb82013-09-18 15:10:16 -0700767 * {@link #closeWithError(String)}.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700768 * @see #canDetectErrors()
769 */
Amith Yamasanib433bb82013-09-18 15:10:16 -0700770 public void checkError() throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700771 if (mWrapped != null) {
Amith Yamasanib433bb82013-09-18 15:10:16 -0700772 mWrapped.checkError();
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700773 } else {
774 if (mStatus == null) {
775 if (mCommFd == null) {
776 Log.w(TAG, "Peer didn't provide a comm channel; unable to check for errors");
777 return;
778 }
779
780 // Try reading status; it might be null if nothing written yet.
781 // Either way, we keep comm open to write our status later.
782 mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer());
783 }
784
Amith Yamasanib433bb82013-09-18 15:10:16 -0700785 if (mStatus == null || mStatus.status == Status.OK) {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700786 // No status yet, or everything is peachy!
787 return;
788 } else {
789 throw mStatus.asIOException();
790 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800791 }
792 }
Elliott Hughes43907582011-04-12 14:25:23 -0700793
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794 /**
795 * An InputStream you can create on a ParcelFileDescriptor, which will
796 * take care of calling {@link ParcelFileDescriptor#close
Christopher Tatefa9e7c02010-05-06 12:07:10 -0700797 * ParcelFileDescriptor.close()} for you when the stream is closed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800798 */
799 public static class AutoCloseInputStream extends FileInputStream {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700800 private final ParcelFileDescriptor mPfd;
Elliott Hughes43907582011-04-12 14:25:23 -0700801
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700802 public AutoCloseInputStream(ParcelFileDescriptor pfd) {
803 super(pfd.getFileDescriptor());
804 mPfd = pfd;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800805 }
806
807 @Override
808 public void close() throws IOException {
Brian Carlstromfd9ddd12010-11-04 11:24:58 -0700809 try {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700810 mPfd.close();
Brian Carlstromfd9ddd12010-11-04 11:24:58 -0700811 } finally {
812 super.close();
813 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800814 }
815 }
Elliott Hughes43907582011-04-12 14:25:23 -0700816
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800817 /**
818 * An OutputStream you can create on a ParcelFileDescriptor, which will
819 * take care of calling {@link ParcelFileDescriptor#close
Christopher Tatefa9e7c02010-05-06 12:07:10 -0700820 * ParcelFileDescriptor.close()} for you when the stream is closed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800821 */
822 public static class AutoCloseOutputStream extends FileOutputStream {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700823 private final ParcelFileDescriptor mPfd;
Elliott Hughes43907582011-04-12 14:25:23 -0700824
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700825 public AutoCloseOutputStream(ParcelFileDescriptor pfd) {
826 super(pfd.getFileDescriptor());
827 mPfd = pfd;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800828 }
829
830 @Override
831 public void close() throws IOException {
Brian Carlstromfd9ddd12010-11-04 11:24:58 -0700832 try {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700833 mPfd.close();
Brian Carlstromfd9ddd12010-11-04 11:24:58 -0700834 } finally {
835 super.close();
836 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800837 }
838 }
Elliott Hughes43907582011-04-12 14:25:23 -0700839
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800840 @Override
841 public String toString() {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700842 if (mWrapped != null) {
843 return mWrapped.toString();
844 } else {
845 return "{ParcelFileDescriptor: " + mFd + "}";
846 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800847 }
Elliott Hughes43907582011-04-12 14:25:23 -0700848
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800849 @Override
850 protected void finalize() throws Throwable {
Amith Yamasani487c11a2013-09-18 09:16:15 -0700851 if (mWrapped != null) {
852 releaseResources();
853 }
Jeff Sharkey7407c942012-11-12 13:42:49 -0800854 if (mGuard != null) {
855 mGuard.warnIfOpen();
856 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800857 try {
858 if (!mClosed) {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700859 closeWithStatus(Status.LEAKED, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800860 }
861 } finally {
862 super.finalize();
863 }
864 }
Elliott Hughes43907582011-04-12 14:25:23 -0700865
Jeff Sharkey7407c942012-11-12 13:42:49 -0800866 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800867 public int describeContents() {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700868 if (mWrapped != null) {
869 return mWrapped.describeContents();
870 } else {
871 return Parcelable.CONTENTS_FILE_DESCRIPTOR;
872 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800873 }
874
Dan Egnorb3e4ef32010-07-20 09:03:35 -0700875 /**
876 * {@inheritDoc}
877 * If {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set in flags,
878 * the file descriptor will be closed after a copy is written to the Parcel.
879 */
Jeff Sharkey7407c942012-11-12 13:42:49 -0800880 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800881 public void writeToParcel(Parcel out, int flags) {
Mike Lockwood8b851642013-09-05 08:47:38 -0700882 // WARNING: This must stay in sync with Parcel::readParcelFileDescriptor()
883 // in frameworks/native/libs/binder/Parcel.cpp
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700884 if (mWrapped != null) {
Amith Yamasani487c11a2013-09-18 09:16:15 -0700885 try {
886 mWrapped.writeToParcel(out, flags);
887 } finally {
888 releaseResources();
889 }
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700890 } else {
891 out.writeFileDescriptor(mFd);
892 if (mCommFd != null) {
893 out.writeInt(1);
894 out.writeFileDescriptor(mCommFd);
895 } else {
896 out.writeInt(0);
897 }
898 if ((flags & PARCELABLE_WRITE_RETURN_VALUE) != 0 && !mClosed) {
Amith Yamasani487c11a2013-09-18 09:16:15 -0700899 // Not a real close, so emit no status
900 closeWithStatus(Status.SILENCE, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800901 }
902 }
903 }
904
905 public static final Parcelable.Creator<ParcelFileDescriptor> CREATOR
906 = new Parcelable.Creator<ParcelFileDescriptor>() {
Jeff Sharkey7407c942012-11-12 13:42:49 -0800907 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800908 public ParcelFileDescriptor createFromParcel(Parcel in) {
Mike Lockwood8b851642013-09-05 08:47:38 -0700909 // WARNING: This must stay in sync with Parcel::writeParcelFileDescriptor()
910 // in frameworks/native/libs/binder/Parcel.cpp
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700911 final FileDescriptor fd = in.readRawFileDescriptor();
912 FileDescriptor commChannel = null;
913 if (in.readInt() != 0) {
914 commChannel = in.readRawFileDescriptor();
915 }
916 return new ParcelFileDescriptor(fd, commChannel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800917 }
Jeff Sharkey7407c942012-11-12 13:42:49 -0800918
919 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800920 public ParcelFileDescriptor[] newArray(int size) {
921 return new ParcelFileDescriptor[size];
922 }
923 };
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700924
925 /**
926 * Callback indicating that a ParcelFileDescriptor has been closed.
927 */
928 public interface OnCloseListener {
929 /**
930 * Event indicating the ParcelFileDescriptor to which this listener was
931 * attached has been closed.
932 *
933 * @param e error state, or {@code null} if closed cleanly.
Amith Yamasanib433bb82013-09-18 15:10:16 -0700934 * If the close event was the result of
935 * {@link ParcelFileDescriptor#detachFd()}, this will be a
936 * {@link FileDescriptorDetachedException}. After detach the
937 * remote side may continue reading/writing to the underlying
938 * {@link FileDescriptor}, but they can no longer deliver
939 * reliable close/error events.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700940 */
Amith Yamasanib433bb82013-09-18 15:10:16 -0700941 public void onClose(IOException e);
942 }
943
944 /**
945 * Exception that indicates that the file descriptor was detached.
946 */
947 public static class FileDescriptorDetachedException extends IOException {
948
949 private static final long serialVersionUID = 0xDe7ac4edFdL;
950
951 public FileDescriptorDetachedException() {
952 super("Remote side is detached");
953 }
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700954 }
955
956 /**
957 * Internal class representing a remote status read by
958 * {@link ParcelFileDescriptor#readCommStatus(FileDescriptor, byte[])}.
959 */
960 private static class Status {
961 /** Special value indicating remote side died. */
962 public static final int DEAD = -2;
963 /** Special value indicating no status should be written. */
964 public static final int SILENCE = -1;
965
966 /** Remote reported that everything went better than expected. */
967 public static final int OK = 0;
968 /** Remote reported error; length and message follow. */
969 public static final int ERROR = 1;
970 /** Remote reported {@link #detachFd()} and went rogue. */
971 public static final int DETACHED = 2;
972 /** Remote reported their object was finalized. */
973 public static final int LEAKED = 3;
974
975 public final int status;
976 public final String msg;
977
978 public Status(int status) {
979 this(status, null);
980 }
981
982 public Status(int status, String msg) {
983 this.status = status;
984 this.msg = msg;
985 }
986
987 public IOException asIOException() {
988 switch (status) {
989 case DEAD:
990 return new IOException("Remote side is dead");
991 case OK:
992 return null;
993 case ERROR:
994 return new IOException("Remote error: " + msg);
995 case DETACHED:
Amith Yamasanib433bb82013-09-18 15:10:16 -0700996 return new FileDescriptorDetachedException();
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700997 case LEAKED:
998 return new IOException("Remote side was leaked");
999 default:
1000 return new IOException("Unknown status: " + status);
1001 }
1002 }
1003 }
1004
1005 /**
1006 * Bridge to watch for remote status, and deliver to listener. Currently
1007 * requires that communication socket is <em>blocking</em>.
1008 */
1009 private static final class ListenerBridge extends Thread {
1010 // TODO: switch to using Looper to avoid burning a thread
1011
1012 private FileDescriptor mCommFd;
1013 private final Handler mHandler;
1014
1015 public ListenerBridge(FileDescriptor comm, Looper looper, final OnCloseListener listener) {
1016 mCommFd = comm;
1017 mHandler = new Handler(looper) {
1018 @Override
1019 public void handleMessage(Message msg) {
1020 final Status s = (Status) msg.obj;
Amith Yamasanib433bb82013-09-18 15:10:16 -07001021 listener.onClose(s != null ? s.asIOException() : null);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001022 }
1023 };
1024 }
1025
1026 @Override
1027 public void run() {
1028 try {
1029 final byte[] buf = new byte[MAX_STATUS];
1030 final Status status = readCommStatus(mCommFd, buf);
1031 mHandler.obtainMessage(0, status).sendToTarget();
1032 } finally {
1033 IoUtils.closeQuietly(mCommFd);
1034 mCommFd = null;
1035 }
1036 }
1037 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001038}