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