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