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