ParcelFileDescriptor.java revision 4bf27b53b97475803fdb85069d500a075aefc801
1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.os; 18 19import static android.system.OsConstants.AF_UNIX; 20import static android.system.OsConstants.SEEK_SET; 21import static android.system.OsConstants.SOCK_STREAM; 22import static android.system.OsConstants.SOCK_SEQPACKET; 23import static android.system.OsConstants.S_ISLNK; 24import static android.system.OsConstants.S_ISREG; 25 26import android.content.BroadcastReceiver; 27import android.content.ContentProvider; 28import android.os.MessageQueue.OnFileDescriptorEventListener; 29import android.system.ErrnoException; 30import android.system.Os; 31import android.system.OsConstants; 32import android.system.StructStat; 33import android.util.Log; 34 35import dalvik.system.CloseGuard; 36import libcore.io.IoUtils; 37import libcore.io.Memory; 38 39import java.io.Closeable; 40import java.io.File; 41import java.io.FileDescriptor; 42import java.io.FileInputStream; 43import java.io.FileNotFoundException; 44import java.io.FileOutputStream; 45import java.io.IOException; 46import java.io.InterruptedIOException; 47import java.net.DatagramSocket; 48import java.net.Socket; 49import java.nio.ByteOrder; 50 51/** 52 * The FileDescriptor returned by {@link Parcel#readFileDescriptor}, allowing 53 * you to close it when done with it. 54 */ 55public class ParcelFileDescriptor implements Parcelable, Closeable { 56 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; 65 66 /** 67 * Wrapped {@link ParcelFileDescriptor}, if any. Used to avoid 68 * double-closing {@link #mFd}. 69 */ 70 private final ParcelFileDescriptor mWrapped; 71 72 /** 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 /** 85 * Status read by {@link #checkError()}, or null if not read yet. 86 */ 87 private Status mStatus; 88 89 private volatile boolean mClosed; 90 91 private final CloseGuard mGuard = CloseGuard.get(); 92 93 /** 94 * 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. 105 */ 106 @Deprecated 107 public static final int MODE_WORLD_READABLE = 0x00000001; 108 109 /** 110 * 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. 121 */ 122 @Deprecated 123 public static final int MODE_WORLD_WRITEABLE = 0x00000002; 124 125 /** 126 * For use with {@link #open}: open the file with read-only access. 127 */ 128 public static final int MODE_READ_ONLY = 0x10000000; 129 130 /** 131 * For use with {@link #open}: open the file with write-only access. 132 */ 133 public static final int MODE_WRITE_ONLY = 0x20000000; 134 135 /** 136 * For use with {@link #open}: open the file with read and write access. 137 */ 138 public static final int MODE_READ_WRITE = 0x30000000; 139 140 /** 141 * For use with {@link #open}: create the file if it doesn't already exist. 142 */ 143 public static final int MODE_CREATE = 0x08000000; 144 145 /** 146 * For use with {@link #open}: erase contents of file when opening. 147 */ 148 public static final int MODE_TRUNCATE = 0x04000000; 149 150 /** 151 * For use with {@link #open}: append to end of file while writing. 152 */ 153 public static final int MODE_APPEND = 0x02000000; 154 155 /** 156 * 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 /** 185 * Create a new ParcelFileDescriptor accessing a given file. 186 * 187 * @param file The file to be opened. 188 * @param mode The desired access mode, must be one of 189 * {@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. 197 * @see #parseMode(String) 198 */ 199 public static ParcelFileDescriptor open(File file, int mode) throws FileNotFoundException { 200 final FileDescriptor fd = openInternal(file, mode); 201 if (fd == null) return null; 202 203 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. 222 * @see #parseMode(String) 223 */ 224 public static ParcelFileDescriptor open(File file, int mode, Handler handler, 225 final OnCloseListener listener) throws IOException { 226 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 236 final FileDescriptor[] comm = createCommSocketPair(); 237 final ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd, comm[0]); 238 final MessageQueue queue = handler.getLooper().getQueue(); 239 queue.addOnFileDescriptorEventListener(comm[1], 240 OnFileDescriptorEventListener.EVENT_INPUT, new OnFileDescriptorEventListener() { 241 @Override 242 public int onFileDescriptorEvents(FileDescriptor fd, int events) { 243 Status status = null; 244 if ((events & OnFileDescriptorEventListener.EVENT_INPUT) != 0) { 245 final byte[] buf = new byte[MAX_STATUS]; 246 status = readCommStatus(fd, buf); 247 } else if ((events & OnFileDescriptorEventListener.EVENT_ERROR) != 0) { 248 status = new Status(Status.DEAD); 249 } 250 if (status != null) { 251 queue.removeOnFileDescriptorEventListener(fd); 252 IoUtils.closeQuietly(fd); 253 listener.onClose(status.asIOException()); 254 return 0; 255 } 256 return EVENT_INPUT; 257 } 258 }); 259 260 return pfd; 261 } 262 263 private static FileDescriptor openInternal(File file, int mode) throws FileNotFoundException { 264 if ((mode & MODE_READ_WRITE) == 0) { 265 throw new IllegalArgumentException( 266 "Must specify MODE_READ_ONLY, MODE_WRITE_ONLY, or MODE_READ_WRITE"); 267 } 268 269 final String path = file.getPath(); 270 return Parcel.openFileDescriptor(path, mode); 271 } 272 273 /** 274 * Create a new ParcelFileDescriptor that is a dup of an existing 275 * FileDescriptor. This obeys standard POSIX semantics, where the 276 * new file descriptor shared state such as file position with the 277 * original file descriptor. 278 */ 279 public static ParcelFileDescriptor dup(FileDescriptor orig) throws IOException { 280 try { 281 final FileDescriptor fd = Os.dup(orig); 282 return new ParcelFileDescriptor(fd); 283 } catch (ErrnoException e) { 284 throw e.rethrowAsIOException(); 285 } 286 } 287 288 /** 289 * Create a new ParcelFileDescriptor that is a dup of the existing 290 * FileDescriptor. This obeys standard POSIX semantics, where the 291 * new file descriptor shared state such as file position with the 292 * original file descriptor. 293 */ 294 public ParcelFileDescriptor dup() throws IOException { 295 if (mWrapped != null) { 296 return mWrapped.dup(); 297 } else { 298 return dup(getFileDescriptor()); 299 } 300 } 301 302 /** 303 * Create a new ParcelFileDescriptor from a raw native fd. The new 304 * ParcelFileDescriptor holds a dup of the original fd passed in here, 305 * so you must still close that fd as well as the new ParcelFileDescriptor. 306 * 307 * @param fd The native fd that the ParcelFileDescriptor should dup. 308 * 309 * @return Returns a new ParcelFileDescriptor holding a FileDescriptor 310 * for a dup of the given fd. 311 */ 312 public static ParcelFileDescriptor fromFd(int fd) throws IOException { 313 final FileDescriptor original = new FileDescriptor(); 314 original.setInt$(fd); 315 316 try { 317 final FileDescriptor dup = Os.dup(original); 318 return new ParcelFileDescriptor(dup); 319 } catch (ErrnoException e) { 320 throw e.rethrowAsIOException(); 321 } 322 } 323 324 /** 325 * Take ownership of a raw native fd in to a new ParcelFileDescriptor. 326 * The returned ParcelFileDescriptor now owns the given fd, and will be 327 * responsible for closing it. You must not close the fd yourself. 328 * 329 * @param fd The native fd that the ParcelFileDescriptor should adopt. 330 * 331 * @return Returns a new ParcelFileDescriptor holding a FileDescriptor 332 * for the given fd. 333 */ 334 public static ParcelFileDescriptor adoptFd(int fd) { 335 final FileDescriptor fdesc = new FileDescriptor(); 336 fdesc.setInt$(fd); 337 338 return new ParcelFileDescriptor(fdesc); 339 } 340 341 /** 342 * Create a new ParcelFileDescriptor from the specified Socket. The new 343 * ParcelFileDescriptor holds a dup of the original FileDescriptor in 344 * the Socket, so you must still close the Socket as well as the new 345 * ParcelFileDescriptor. 346 * 347 * @param socket The Socket whose FileDescriptor is used to create 348 * a new ParcelFileDescriptor. 349 * 350 * @return A new ParcelFileDescriptor with the FileDescriptor of the 351 * specified Socket. 352 */ 353 public static ParcelFileDescriptor fromSocket(Socket socket) { 354 FileDescriptor fd = socket.getFileDescriptor$(); 355 return fd != null ? new ParcelFileDescriptor(fd) : null; 356 } 357 358 /** 359 * Create a new ParcelFileDescriptor from the specified DatagramSocket. 360 * 361 * @param datagramSocket The DatagramSocket whose FileDescriptor is used 362 * to create a new ParcelFileDescriptor. 363 * 364 * @return A new ParcelFileDescriptor with the FileDescriptor of the 365 * specified DatagramSocket. 366 */ 367 public static ParcelFileDescriptor fromDatagramSocket(DatagramSocket datagramSocket) { 368 FileDescriptor fd = datagramSocket.getFileDescriptor$(); 369 return fd != null ? new ParcelFileDescriptor(fd) : null; 370 } 371 372 /** 373 * Create two ParcelFileDescriptors structured as a data pipe. The first 374 * ParcelFileDescriptor in the returned array is the read side; the second 375 * is the write side. 376 */ 377 public static ParcelFileDescriptor[] createPipe() throws IOException { 378 try { 379 final FileDescriptor[] fds = Os.pipe(); 380 return new ParcelFileDescriptor[] { 381 new ParcelFileDescriptor(fds[0]), 382 new ParcelFileDescriptor(fds[1]) }; 383 } catch (ErrnoException e) { 384 throw e.rethrowAsIOException(); 385 } 386 } 387 388 /** 389 * Create two ParcelFileDescriptors structured as a data pipe. The first 390 * ParcelFileDescriptor in the returned array is the read side; the second 391 * is the write side. 392 * <p> 393 * The write end has the ability to deliver an error message through 394 * {@link #closeWithError(String)} which can be handled by the read end 395 * calling {@link #checkError()}, usually after detecting an EOF. 396 * This can also be used to detect remote crashes. 397 */ 398 public static ParcelFileDescriptor[] createReliablePipe() throws IOException { 399 try { 400 final FileDescriptor[] comm = createCommSocketPair(); 401 final FileDescriptor[] fds = Os.pipe(); 402 return new ParcelFileDescriptor[] { 403 new ParcelFileDescriptor(fds[0], comm[0]), 404 new ParcelFileDescriptor(fds[1], comm[1]) }; 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 */ 414 public static ParcelFileDescriptor[] createSocketPair() throws IOException { 415 return createSocketPair(SOCK_STREAM); 416 } 417 418 /** 419 * @hide 420 */ 421 public static ParcelFileDescriptor[] createSocketPair(int type) throws IOException { 422 try { 423 final FileDescriptor fd0 = new FileDescriptor(); 424 final FileDescriptor fd1 = new FileDescriptor(); 425 Os.socketpair(AF_UNIX, type, 0, fd0, fd1); 426 return new ParcelFileDescriptor[] { 427 new ParcelFileDescriptor(fd0), 428 new ParcelFileDescriptor(fd1) }; 429 } catch (ErrnoException e) { 430 throw e.rethrowAsIOException(); 431 } 432 } 433 434 /** 435 * Create two ParcelFileDescriptors structured as a pair of sockets 436 * connected to each other. The two sockets are indistinguishable. 437 * <p> 438 * Both ends have the ability to deliver an error message through 439 * {@link #closeWithError(String)} which can be detected by the other end 440 * calling {@link #checkError()}, usually after detecting an EOF. 441 * This can also be used to detect remote crashes. 442 */ 443 public static ParcelFileDescriptor[] createReliableSocketPair() throws IOException { 444 return createReliableSocketPair(SOCK_STREAM); 445 } 446 447 /** 448 * @hide 449 */ 450 public static ParcelFileDescriptor[] createReliableSocketPair(int type) throws IOException { 451 try { 452 final FileDescriptor[] comm = createCommSocketPair(); 453 final FileDescriptor fd0 = new FileDescriptor(); 454 final FileDescriptor fd1 = new FileDescriptor(); 455 Os.socketpair(AF_UNIX, type, 0, fd0, fd1); 456 return new ParcelFileDescriptor[] { 457 new ParcelFileDescriptor(fd0, comm[0]), 458 new ParcelFileDescriptor(fd1, comm[1]) }; 459 } catch (ErrnoException e) { 460 throw e.rethrowAsIOException(); 461 } 462 } 463 464 private static FileDescriptor[] createCommSocketPair() throws IOException { 465 try { 466 // Use SOCK_SEQPACKET so that we have a guarantee that the status 467 // is written and read atomically as one unit and is not split 468 // across multiple IO operations. 469 final FileDescriptor comm1 = new FileDescriptor(); 470 final FileDescriptor comm2 = new FileDescriptor(); 471 Os.socketpair(AF_UNIX, SOCK_SEQPACKET, 0, comm1, comm2); 472 IoUtils.setBlocking(comm1, false); 473 IoUtils.setBlocking(comm2, false); 474 return new FileDescriptor[] { comm1, comm2 }; 475 } catch (ErrnoException e) { 476 throw e.rethrowAsIOException(); 477 } 478 } 479 480 /** 481 * @hide Please use createPipe() or ContentProvider.openPipeHelper(). 482 * Gets a file descriptor for a read-only copy of the given data. 483 * 484 * @param data Data to copy. 485 * @param name Name for the shared memory area that may back the file descriptor. 486 * This is purely informative and may be {@code null}. 487 * @return A ParcelFileDescriptor. 488 * @throws IOException if there is an error while creating the shared memory area. 489 */ 490 @Deprecated 491 public static ParcelFileDescriptor fromData(byte[] data, String name) throws IOException { 492 if (data == null) return null; 493 MemoryFile file = new MemoryFile(name, data.length); 494 if (data.length > 0) { 495 file.writeBytes(data, 0, 0, data.length); 496 } 497 file.deactivate(); 498 FileDescriptor fd = file.getFileDescriptor(); 499 return fd != null ? new ParcelFileDescriptor(fd) : null; 500 } 501 502 /** 503 * Converts a string representing a file mode, such as "rw", into a bitmask suitable for use 504 * with {@link #open}. 505 * <p> 506 * @param mode The string representation of the file mode. 507 * @return A bitmask representing the given file mode. 508 * @throws IllegalArgumentException if the given string does not match a known file mode. 509 */ 510 public static int parseMode(String mode) { 511 final int modeBits; 512 if ("r".equals(mode)) { 513 modeBits = ParcelFileDescriptor.MODE_READ_ONLY; 514 } else if ("w".equals(mode) || "wt".equals(mode)) { 515 modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY 516 | ParcelFileDescriptor.MODE_CREATE 517 | ParcelFileDescriptor.MODE_TRUNCATE; 518 } else if ("wa".equals(mode)) { 519 modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY 520 | ParcelFileDescriptor.MODE_CREATE 521 | ParcelFileDescriptor.MODE_APPEND; 522 } else if ("rw".equals(mode)) { 523 modeBits = ParcelFileDescriptor.MODE_READ_WRITE 524 | ParcelFileDescriptor.MODE_CREATE; 525 } else if ("rwt".equals(mode)) { 526 modeBits = ParcelFileDescriptor.MODE_READ_WRITE 527 | ParcelFileDescriptor.MODE_CREATE 528 | ParcelFileDescriptor.MODE_TRUNCATE; 529 } else { 530 throw new IllegalArgumentException("Bad mode '" + mode + "'"); 531 } 532 return modeBits; 533 } 534 535 /** 536 * Retrieve the actual FileDescriptor associated with this object. 537 * 538 * @return Returns the FileDescriptor associated with this object. 539 */ 540 public FileDescriptor getFileDescriptor() { 541 if (mWrapped != null) { 542 return mWrapped.getFileDescriptor(); 543 } else { 544 return mFd; 545 } 546 } 547 548 /** 549 * Return the total size of the file representing this fd, as determined by 550 * {@code stat()}. Returns -1 if the fd is not a file. 551 */ 552 public long getStatSize() { 553 if (mWrapped != null) { 554 return mWrapped.getStatSize(); 555 } else { 556 try { 557 final StructStat st = Os.fstat(mFd); 558 if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) { 559 return st.st_size; 560 } else { 561 return -1; 562 } 563 } catch (ErrnoException e) { 564 Log.w(TAG, "fstat() failed: " + e); 565 return -1; 566 } 567 } 568 } 569 570 /** 571 * This is needed for implementing AssetFileDescriptor.AutoCloseOutputStream, 572 * and I really don't think we want it to be public. 573 * @hide 574 */ 575 public long seekTo(long pos) throws IOException { 576 if (mWrapped != null) { 577 return mWrapped.seekTo(pos); 578 } else { 579 try { 580 return Os.lseek(mFd, pos, SEEK_SET); 581 } catch (ErrnoException e) { 582 throw e.rethrowAsIOException(); 583 } 584 } 585 } 586 587 /** 588 * Return the native fd int for this ParcelFileDescriptor. The 589 * ParcelFileDescriptor still owns the fd, and it still must be closed 590 * through this API. 591 */ 592 public int getFd() { 593 if (mWrapped != null) { 594 return mWrapped.getFd(); 595 } else { 596 if (mClosed) { 597 throw new IllegalStateException("Already closed"); 598 } 599 return mFd.getInt$(); 600 } 601 } 602 603 /** 604 * Return the native fd int for this ParcelFileDescriptor and detach it from 605 * the object here. You are now responsible for closing the fd in native 606 * code. 607 * <p> 608 * You should not detach when the original creator of the descriptor is 609 * expecting a reliable signal through {@link #close()} or 610 * {@link #closeWithError(String)}. 611 * 612 * @see #canDetectErrors() 613 */ 614 public int detachFd() { 615 if (mWrapped != null) { 616 return mWrapped.detachFd(); 617 } else { 618 if (mClosed) { 619 throw new IllegalStateException("Already closed"); 620 } 621 final int fd = getFd(); 622 Parcel.clearFileDescriptor(mFd); 623 writeCommStatusAndClose(Status.DETACHED, null); 624 return fd; 625 } 626 } 627 628 /** 629 * Close the ParcelFileDescriptor. This implementation closes the underlying 630 * OS resources allocated to represent this stream. 631 * 632 * @throws IOException 633 * If an error occurs attempting to close this ParcelFileDescriptor. 634 */ 635 @Override 636 public void close() throws IOException { 637 if (mWrapped != null) { 638 try { 639 mWrapped.close(); 640 } finally { 641 releaseResources(); 642 } 643 } else { 644 closeWithStatus(Status.OK, null); 645 } 646 } 647 648 /** 649 * Close the ParcelFileDescriptor, informing any peer that an error occurred 650 * while processing. If the creator of this descriptor is not observing 651 * errors, it will close normally. 652 * 653 * @param msg describing the error; must not be null. 654 */ 655 public void closeWithError(String msg) throws IOException { 656 if (mWrapped != null) { 657 try { 658 mWrapped.closeWithError(msg); 659 } finally { 660 releaseResources(); 661 } 662 } else { 663 if (msg == null) { 664 throw new IllegalArgumentException("Message must not be null"); 665 } 666 closeWithStatus(Status.ERROR, msg); 667 } 668 } 669 670 private void closeWithStatus(int status, String msg) { 671 if (mClosed) return; 672 mClosed = true; 673 mGuard.close(); 674 // Status MUST be sent before closing actual descriptor 675 writeCommStatusAndClose(status, msg); 676 IoUtils.closeQuietly(mFd); 677 releaseResources(); 678 } 679 680 /** 681 * Called when the fd is being closed, for subclasses to release any other resources 682 * associated with it, such as acquired providers. 683 * @hide 684 */ 685 public void releaseResources() { 686 } 687 688 private byte[] getOrCreateStatusBuffer() { 689 if (mStatusBuf == null) { 690 mStatusBuf = new byte[MAX_STATUS]; 691 } 692 return mStatusBuf; 693 } 694 695 private void writeCommStatusAndClose(int status, String msg) { 696 if (mCommFd == null) { 697 // Not reliable, or someone already sent status 698 if (msg != null) { 699 Log.w(TAG, "Unable to inform peer: " + msg); 700 } 701 return; 702 } 703 704 if (status == Status.DETACHED) { 705 Log.w(TAG, "Peer expected signal when closed; unable to deliver after detach"); 706 } 707 708 try { 709 if (status == Status.SILENCE) return; 710 711 // Since we're about to close, read off any remote status. It's 712 // okay to remember missing here. 713 mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer()); 714 715 // Skip writing status when other end has already gone away. 716 if (mStatus != null) return; 717 718 try { 719 final byte[] buf = getOrCreateStatusBuffer(); 720 int writePtr = 0; 721 722 Memory.pokeInt(buf, writePtr, status, ByteOrder.BIG_ENDIAN); 723 writePtr += 4; 724 725 if (msg != null) { 726 final byte[] rawMsg = msg.getBytes(); 727 final int len = Math.min(rawMsg.length, buf.length - writePtr); 728 System.arraycopy(rawMsg, 0, buf, writePtr, len); 729 writePtr += len; 730 } 731 732 // Must write the entire status as a single operation. 733 Os.write(mCommFd, buf, 0, writePtr); 734 } catch (ErrnoException e) { 735 // Reporting status is best-effort 736 Log.w(TAG, "Failed to report status: " + e); 737 } catch (InterruptedIOException e) { 738 // Reporting status is best-effort 739 Log.w(TAG, "Failed to report status: " + e); 740 } 741 742 } finally { 743 IoUtils.closeQuietly(mCommFd); 744 mCommFd = null; 745 } 746 } 747 748 private static Status readCommStatus(FileDescriptor comm, byte[] buf) { 749 try { 750 // Must read the entire status as a single operation. 751 final int n = Os.read(comm, buf, 0, buf.length); 752 if (n == 0) { 753 // EOF means they're dead 754 return new Status(Status.DEAD); 755 } else { 756 final int status = Memory.peekInt(buf, 0, ByteOrder.BIG_ENDIAN); 757 if (status == Status.ERROR) { 758 final String msg = new String(buf, 4, n - 4); 759 return new Status(status, msg); 760 } 761 return new Status(status); 762 } 763 } catch (ErrnoException e) { 764 if (e.errno == OsConstants.EAGAIN) { 765 // Remote is still alive, but no status written yet 766 return null; 767 } else { 768 Log.d(TAG, "Failed to read status; assuming dead: " + e); 769 return new Status(Status.DEAD); 770 } 771 } catch (InterruptedIOException e) { 772 Log.d(TAG, "Failed to read status; assuming dead: " + e); 773 return new Status(Status.DEAD); 774 } 775 } 776 777 /** 778 * Indicates if this ParcelFileDescriptor can communicate and detect remote 779 * errors/crashes. 780 * 781 * @see #checkError() 782 */ 783 public boolean canDetectErrors() { 784 if (mWrapped != null) { 785 return mWrapped.canDetectErrors(); 786 } else { 787 return mCommFd != null; 788 } 789 } 790 791 /** 792 * Detect and throw if the other end of a pipe or socket pair encountered an 793 * error or crashed. This allows a reader to distinguish between a valid EOF 794 * and an error/crash. 795 * <p> 796 * If this ParcelFileDescriptor is unable to detect remote errors, it will 797 * return silently. 798 * 799 * @throws IOException for normal errors. 800 * @throws FileDescriptorDetachedException 801 * if the remote side called {@link #detachFd()}. Once detached, the remote 802 * side is unable to communicate any errors through 803 * {@link #closeWithError(String)}. 804 * @see #canDetectErrors() 805 */ 806 public void checkError() throws IOException { 807 if (mWrapped != null) { 808 mWrapped.checkError(); 809 } else { 810 if (mStatus == null) { 811 if (mCommFd == null) { 812 Log.w(TAG, "Peer didn't provide a comm channel; unable to check for errors"); 813 return; 814 } 815 816 // Try reading status; it might be null if nothing written yet. 817 // Either way, we keep comm open to write our status later. 818 mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer()); 819 } 820 821 if (mStatus == null || mStatus.status == Status.OK) { 822 // No status yet, or everything is peachy! 823 return; 824 } else { 825 throw mStatus.asIOException(); 826 } 827 } 828 } 829 830 /** 831 * An InputStream you can create on a ParcelFileDescriptor, which will 832 * take care of calling {@link ParcelFileDescriptor#close 833 * ParcelFileDescriptor.close()} for you when the stream is closed. 834 */ 835 public static class AutoCloseInputStream extends FileInputStream { 836 private final ParcelFileDescriptor mPfd; 837 838 public AutoCloseInputStream(ParcelFileDescriptor pfd) { 839 super(pfd.getFileDescriptor()); 840 mPfd = pfd; 841 } 842 843 @Override 844 public void close() throws IOException { 845 try { 846 mPfd.close(); 847 } finally { 848 super.close(); 849 } 850 } 851 } 852 853 /** 854 * An OutputStream you can create on a ParcelFileDescriptor, which will 855 * take care of calling {@link ParcelFileDescriptor#close 856 * ParcelFileDescriptor.close()} for you when the stream is closed. 857 */ 858 public static class AutoCloseOutputStream extends FileOutputStream { 859 private final ParcelFileDescriptor mPfd; 860 861 public AutoCloseOutputStream(ParcelFileDescriptor pfd) { 862 super(pfd.getFileDescriptor()); 863 mPfd = pfd; 864 } 865 866 @Override 867 public void close() throws IOException { 868 try { 869 mPfd.close(); 870 } finally { 871 super.close(); 872 } 873 } 874 } 875 876 @Override 877 public String toString() { 878 if (mWrapped != null) { 879 return mWrapped.toString(); 880 } else { 881 return "{ParcelFileDescriptor: " + mFd + "}"; 882 } 883 } 884 885 @Override 886 protected void finalize() throws Throwable { 887 if (mWrapped != null) { 888 releaseResources(); 889 } 890 if (mGuard != null) { 891 mGuard.warnIfOpen(); 892 } 893 try { 894 if (!mClosed) { 895 closeWithStatus(Status.LEAKED, null); 896 } 897 } finally { 898 super.finalize(); 899 } 900 } 901 902 @Override 903 public int describeContents() { 904 if (mWrapped != null) { 905 return mWrapped.describeContents(); 906 } else { 907 return Parcelable.CONTENTS_FILE_DESCRIPTOR; 908 } 909 } 910 911 /** 912 * {@inheritDoc} 913 * If {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set in flags, 914 * the file descriptor will be closed after a copy is written to the Parcel. 915 */ 916 @Override 917 public void writeToParcel(Parcel out, int flags) { 918 if (mWrapped != null) { 919 try { 920 mWrapped.writeToParcel(out, flags); 921 } finally { 922 releaseResources(); 923 } 924 } else { 925 if (mCommFd != null) { 926 out.writeInt(1); 927 out.writeFileDescriptor(mFd); 928 out.writeFileDescriptor(mCommFd); 929 } else { 930 out.writeInt(0); 931 out.writeFileDescriptor(mFd); 932 } 933 if ((flags & PARCELABLE_WRITE_RETURN_VALUE) != 0 && !mClosed) { 934 // Not a real close, so emit no status 935 closeWithStatus(Status.SILENCE, null); 936 } 937 } 938 } 939 940 public static final Parcelable.Creator<ParcelFileDescriptor> CREATOR 941 = new Parcelable.Creator<ParcelFileDescriptor>() { 942 @Override 943 public ParcelFileDescriptor createFromParcel(Parcel in) { 944 int hasCommChannel = in.readInt(); 945 final FileDescriptor fd = in.readRawFileDescriptor(); 946 FileDescriptor commChannel = null; 947 if (hasCommChannel != 0) { 948 commChannel = in.readRawFileDescriptor(); 949 } 950 return new ParcelFileDescriptor(fd, commChannel); 951 } 952 953 @Override 954 public ParcelFileDescriptor[] newArray(int size) { 955 return new ParcelFileDescriptor[size]; 956 } 957 }; 958 959 /** 960 * Callback indicating that a ParcelFileDescriptor has been closed. 961 */ 962 public interface OnCloseListener { 963 /** 964 * Event indicating the ParcelFileDescriptor to which this listener was 965 * attached has been closed. 966 * 967 * @param e error state, or {@code null} if closed cleanly. 968 * If the close event was the result of 969 * {@link ParcelFileDescriptor#detachFd()}, this will be a 970 * {@link FileDescriptorDetachedException}. After detach the 971 * remote side may continue reading/writing to the underlying 972 * {@link FileDescriptor}, but they can no longer deliver 973 * reliable close/error events. 974 */ 975 public void onClose(IOException e); 976 } 977 978 /** 979 * Exception that indicates that the file descriptor was detached. 980 */ 981 public static class FileDescriptorDetachedException extends IOException { 982 983 private static final long serialVersionUID = 0xDe7ac4edFdL; 984 985 public FileDescriptorDetachedException() { 986 super("Remote side is detached"); 987 } 988 } 989 990 /** 991 * Internal class representing a remote status read by 992 * {@link ParcelFileDescriptor#readCommStatus(FileDescriptor, byte[])}. 993 */ 994 private static class Status { 995 /** Special value indicating remote side died. */ 996 public static final int DEAD = -2; 997 /** Special value indicating no status should be written. */ 998 public static final int SILENCE = -1; 999 1000 /** Remote reported that everything went better than expected. */ 1001 public static final int OK = 0; 1002 /** Remote reported error; length and message follow. */ 1003 public static final int ERROR = 1; 1004 /** Remote reported {@link #detachFd()} and went rogue. */ 1005 public static final int DETACHED = 2; 1006 /** Remote reported their object was finalized. */ 1007 public static final int LEAKED = 3; 1008 1009 public final int status; 1010 public final String msg; 1011 1012 public Status(int status) { 1013 this(status, null); 1014 } 1015 1016 public Status(int status, String msg) { 1017 this.status = status; 1018 this.msg = msg; 1019 } 1020 1021 public IOException asIOException() { 1022 switch (status) { 1023 case DEAD: 1024 return new IOException("Remote side is dead"); 1025 case OK: 1026 return null; 1027 case ERROR: 1028 return new IOException("Remote error: " + msg); 1029 case DETACHED: 1030 return new FileDescriptorDetachedException(); 1031 case LEAKED: 1032 return new IOException("Remote side was leaked"); 1033 default: 1034 return new IOException("Unknown status: " + status); 1035 } 1036 } 1037 1038 @Override 1039 public String toString() { 1040 return "{" + status + ": " + msg + "}"; 1041 } 1042 } 1043} 1044