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