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.F_DUPFD; 21 import static android.system.OsConstants.F_DUPFD_CLOEXEC; 22 import static android.system.OsConstants.O_CLOEXEC; 23 import static android.system.OsConstants.SEEK_SET; 24 import static android.system.OsConstants.SOCK_CLOEXEC; 25 import static android.system.OsConstants.SOCK_SEQPACKET; 26 import static android.system.OsConstants.SOCK_STREAM; 27 import static android.system.OsConstants.S_IROTH; 28 import static android.system.OsConstants.S_IRWXG; 29 import static android.system.OsConstants.S_IRWXU; 30 import static android.system.OsConstants.S_ISLNK; 31 import static android.system.OsConstants.S_ISREG; 32 import static android.system.OsConstants.S_IWOTH; 33 34 import android.annotation.TestApi; 35 import android.annotation.UnsupportedAppUsage; 36 import android.content.BroadcastReceiver; 37 import android.content.ContentProvider; 38 import android.os.MessageQueue.OnFileDescriptorEventListener; 39 import android.system.ErrnoException; 40 import android.system.Os; 41 import android.system.OsConstants; 42 import android.system.StructStat; 43 import android.util.Log; 44 45 import dalvik.system.CloseGuard; 46 import dalvik.system.VMRuntime; 47 48 import libcore.io.IoUtils; 49 import libcore.io.Memory; 50 51 import java.io.Closeable; 52 import java.io.File; 53 import java.io.FileDescriptor; 54 import java.io.FileInputStream; 55 import java.io.FileNotFoundException; 56 import java.io.FileOutputStream; 57 import java.io.IOException; 58 import java.io.InterruptedIOException; 59 import java.io.UncheckedIOException; 60 import java.net.DatagramSocket; 61 import java.net.Socket; 62 import java.nio.ByteOrder; 63 64 /** 65 * The FileDescriptor returned by {@link Parcel#readFileDescriptor}, allowing 66 * you to close it when done with it. 67 */ 68 public class ParcelFileDescriptor implements Parcelable, Closeable { 69 private static final String TAG = "ParcelFileDescriptor"; 70 71 private final FileDescriptor mFd; 72 73 /** 74 * Optional socket used to communicate close events, status at close, and 75 * detect remote process crashes. 76 */ 77 private FileDescriptor mCommFd; 78 79 /** 80 * Wrapped {@link ParcelFileDescriptor}, if any. Used to avoid 81 * double-closing {@link #mFd}. 82 */ 83 private final ParcelFileDescriptor mWrapped; 84 85 /** 86 * Maximum {@link #mStatusBuf} size; longer status messages will be 87 * truncated. 88 */ 89 private static final int MAX_STATUS = 1024; 90 91 /** 92 * Temporary buffer used by {@link #readCommStatus(FileDescriptor, byte[])}, 93 * allocated on-demand. 94 */ 95 private byte[] mStatusBuf; 96 97 /** 98 * Status read by {@link #checkError()}, or null if not read yet. 99 */ 100 private Status mStatus; 101 102 private volatile boolean mClosed; 103 104 private final CloseGuard mGuard = CloseGuard.get(); 105 106 /** 107 * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied and 108 * this file doesn't already exist, then create the file with permissions 109 * such that any application can read it. 110 * 111 * @deprecated Creating world-readable files is very dangerous, and likely 112 * to cause security holes in applications. It is strongly 113 * discouraged; instead, applications should use more formal 114 * mechanism for interactions such as {@link ContentProvider}, 115 * {@link BroadcastReceiver}, and {@link android.app.Service}. 116 * There are no guarantees that this access mode will remain on 117 * a file, such as when it goes through a backup and restore. 118 */ 119 @Deprecated 120 public static final int MODE_WORLD_READABLE = 0x00000001; 121 122 /** 123 * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied and 124 * this file doesn't already exist, then create the file with permissions 125 * such that any application can write it. 126 * 127 * @deprecated Creating world-writable files is very dangerous, and likely 128 * to cause security holes in applications. It is strongly 129 * discouraged; instead, applications should use more formal 130 * mechanism for interactions such as {@link ContentProvider}, 131 * {@link BroadcastReceiver}, and {@link android.app.Service}. 132 * There are no guarantees that this access mode will remain on 133 * a file, such as when it goes through a backup and restore. 134 */ 135 @Deprecated 136 public static final int MODE_WORLD_WRITEABLE = 0x00000002; 137 138 /** 139 * For use with {@link #open}: open the file with read-only access. 140 */ 141 public static final int MODE_READ_ONLY = 0x10000000; 142 143 /** 144 * For use with {@link #open}: open the file with write-only access. 145 */ 146 public static final int MODE_WRITE_ONLY = 0x20000000; 147 148 /** 149 * For use with {@link #open}: open the file with read and write access. 150 */ 151 public static final int MODE_READ_WRITE = 0x30000000; 152 153 /** 154 * For use with {@link #open}: create the file if it doesn't already exist. 155 */ 156 public static final int MODE_CREATE = 0x08000000; 157 158 /** 159 * For use with {@link #open}: erase contents of file when opening. 160 */ 161 public static final int MODE_TRUNCATE = 0x04000000; 162 163 /** 164 * For use with {@link #open}: append to end of file while writing. 165 */ 166 public static final int MODE_APPEND = 0x02000000; 167 168 /** 169 * Create a new ParcelFileDescriptor wrapped around another descriptor. By 170 * default all method calls are delegated to the wrapped descriptor. 171 */ ParcelFileDescriptor(ParcelFileDescriptor wrapped)172 public ParcelFileDescriptor(ParcelFileDescriptor wrapped) { 173 // We keep a strong reference to the wrapped PFD, and rely on its 174 // finalizer to trigger CloseGuard. All calls are delegated to wrapper. 175 mWrapped = wrapped; 176 mFd = null; 177 mCommFd = null; 178 mClosed = true; 179 } 180 181 /** {@hide} */ 182 @UnsupportedAppUsage ParcelFileDescriptor(FileDescriptor fd)183 public ParcelFileDescriptor(FileDescriptor fd) { 184 this(fd, null); 185 } 186 187 /** {@hide} */ ParcelFileDescriptor(FileDescriptor fd, FileDescriptor commChannel)188 public ParcelFileDescriptor(FileDescriptor fd, FileDescriptor commChannel) { 189 if (fd == null) { 190 throw new NullPointerException("FileDescriptor must not be null"); 191 } 192 mWrapped = null; 193 mFd = fd; 194 IoUtils.setFdOwner(mFd, this); 195 196 mCommFd = commChannel; 197 if (mCommFd != null) { 198 IoUtils.setFdOwner(mCommFd, this); 199 } 200 201 mGuard.open("close"); 202 } 203 204 /** 205 * Create a new ParcelFileDescriptor accessing a given file. 206 * 207 * @param file The file to be opened. 208 * @param mode The desired access mode, must be one of 209 * {@link #MODE_READ_ONLY}, {@link #MODE_WRITE_ONLY}, or 210 * {@link #MODE_READ_WRITE}; may also be any combination of 211 * {@link #MODE_CREATE}, {@link #MODE_TRUNCATE}, 212 * {@link #MODE_WORLD_READABLE}, and 213 * {@link #MODE_WORLD_WRITEABLE}. 214 * @return a new ParcelFileDescriptor pointing to the given file. 215 * @throws FileNotFoundException if the given file does not exist or can not 216 * be opened with the requested mode. 217 * @see #parseMode(String) 218 */ open(File file, int mode)219 public static ParcelFileDescriptor open(File file, int mode) throws FileNotFoundException { 220 final FileDescriptor fd = openInternal(file, mode); 221 if (fd == null) return null; 222 223 return new ParcelFileDescriptor(fd); 224 } 225 226 /** 227 * Create a new ParcelFileDescriptor accessing a given file. 228 * 229 * @param file The file to be opened. 230 * @param mode The desired access mode, must be one of 231 * {@link #MODE_READ_ONLY}, {@link #MODE_WRITE_ONLY}, or 232 * {@link #MODE_READ_WRITE}; may also be any combination of 233 * {@link #MODE_CREATE}, {@link #MODE_TRUNCATE}, 234 * {@link #MODE_WORLD_READABLE}, and 235 * {@link #MODE_WORLD_WRITEABLE}. 236 * @param handler to call listener from; must not be null. 237 * @param listener to be invoked when the returned descriptor has been 238 * closed; must not be null. 239 * @return a new ParcelFileDescriptor pointing to the given file. 240 * @throws FileNotFoundException if the given file does not exist or can not 241 * be opened with the requested mode. 242 * @see #parseMode(String) 243 */ open(File file, int mode, Handler handler, final OnCloseListener listener)244 public static ParcelFileDescriptor open(File file, int mode, Handler handler, 245 final OnCloseListener listener) throws IOException { 246 if (handler == null) { 247 throw new IllegalArgumentException("Handler must not be null"); 248 } 249 if (listener == null) { 250 throw new IllegalArgumentException("Listener must not be null"); 251 } 252 253 final FileDescriptor fd = openInternal(file, mode); 254 if (fd == null) return null; 255 256 return fromFd(fd, handler, listener); 257 } 258 259 /** {@hide} */ fromPfd(ParcelFileDescriptor pfd, Handler handler, final OnCloseListener listener)260 public static ParcelFileDescriptor fromPfd(ParcelFileDescriptor pfd, Handler handler, 261 final OnCloseListener listener) throws IOException { 262 final FileDescriptor original = new FileDescriptor(); 263 original.setInt$(pfd.detachFd()); 264 return fromFd(original, handler, listener); 265 } 266 267 /** {@hide} */ fromFd(FileDescriptor fd, Handler handler, final OnCloseListener listener)268 public static ParcelFileDescriptor fromFd(FileDescriptor fd, Handler handler, 269 final OnCloseListener listener) throws IOException { 270 if (handler == null) { 271 throw new IllegalArgumentException("Handler must not be null"); 272 } 273 if (listener == null) { 274 throw new IllegalArgumentException("Listener must not be null"); 275 } 276 277 final FileDescriptor[] comm = createCommSocketPair(); 278 final ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd, comm[0]); 279 final MessageQueue queue = handler.getLooper().getQueue(); 280 queue.addOnFileDescriptorEventListener(comm[1], 281 OnFileDescriptorEventListener.EVENT_INPUT, new OnFileDescriptorEventListener() { 282 @Override 283 public int onFileDescriptorEvents(FileDescriptor fd, int events) { 284 Status status = null; 285 if ((events & OnFileDescriptorEventListener.EVENT_INPUT) != 0) { 286 final byte[] buf = new byte[MAX_STATUS]; 287 status = readCommStatus(fd, buf); 288 } else if ((events & OnFileDescriptorEventListener.EVENT_ERROR) != 0) { 289 status = new Status(Status.DEAD); 290 } 291 if (status != null) { 292 queue.removeOnFileDescriptorEventListener(fd); 293 IoUtils.closeQuietly(fd); 294 listener.onClose(status.asIOException()); 295 return 0; 296 } 297 return EVENT_INPUT; 298 } 299 }); 300 301 return pfd; 302 } 303 openInternal(File file, int mode)304 private static FileDescriptor openInternal(File file, int mode) throws FileNotFoundException { 305 final int flags = FileUtils.translateModePfdToPosix(mode) | ifAtLeastQ(O_CLOEXEC); 306 307 int realMode = S_IRWXU | S_IRWXG; 308 if ((mode & MODE_WORLD_READABLE) != 0) realMode |= S_IROTH; 309 if ((mode & MODE_WORLD_WRITEABLE) != 0) realMode |= S_IWOTH; 310 311 final String path = file.getPath(); 312 try { 313 return Os.open(path, flags, realMode); 314 } catch (ErrnoException e) { 315 throw new FileNotFoundException(e.getMessage()); 316 } 317 } 318 319 /** 320 * Create a new ParcelFileDescriptor that is a dup of an existing 321 * FileDescriptor. This obeys standard POSIX semantics, where the 322 * new file descriptor shared state such as file position with the 323 * original file descriptor. 324 */ dup(FileDescriptor orig)325 public static ParcelFileDescriptor dup(FileDescriptor orig) throws IOException { 326 try { 327 final FileDescriptor fd = new FileDescriptor(); 328 int intfd = Os.fcntlInt(orig, (isAtLeastQ() ? F_DUPFD_CLOEXEC : F_DUPFD), 0); 329 fd.setInt$(intfd); 330 return new ParcelFileDescriptor(fd); 331 } catch (ErrnoException e) { 332 throw e.rethrowAsIOException(); 333 } 334 } 335 336 /** 337 * Create a new ParcelFileDescriptor that is a dup of the existing 338 * FileDescriptor. This obeys standard POSIX semantics, where the 339 * new file descriptor shared state such as file position with the 340 * original file descriptor. 341 */ dup()342 public ParcelFileDescriptor dup() throws IOException { 343 if (mWrapped != null) { 344 return mWrapped.dup(); 345 } else { 346 return dup(getFileDescriptor()); 347 } 348 } 349 350 /** 351 * Create a new ParcelFileDescriptor from a raw native fd. The new 352 * ParcelFileDescriptor holds a dup of the original fd passed in here, 353 * so you must still close that fd as well as the new ParcelFileDescriptor. 354 * 355 * @param fd The native fd that the ParcelFileDescriptor should dup. 356 * 357 * @return Returns a new ParcelFileDescriptor holding a FileDescriptor 358 * for a dup of the given fd. 359 */ fromFd(int fd)360 public static ParcelFileDescriptor fromFd(int fd) throws IOException { 361 final FileDescriptor original = new FileDescriptor(); 362 original.setInt$(fd); 363 364 try { 365 final FileDescriptor dup = new FileDescriptor(); 366 int intfd = Os.fcntlInt(original, (isAtLeastQ() ? F_DUPFD_CLOEXEC : F_DUPFD), 0); 367 dup.setInt$(intfd); 368 return new ParcelFileDescriptor(dup); 369 } catch (ErrnoException e) { 370 throw e.rethrowAsIOException(); 371 } 372 } 373 374 /** 375 * Take ownership of a raw native fd in to a new ParcelFileDescriptor. 376 * The returned ParcelFileDescriptor now owns the given fd, and will be 377 * responsible for closing it. 378 * <p> 379 * <strong>WARNING:</strong> You must not close the fd yourself after 380 * this call, and ownership of the file descriptor must have been 381 * released prior to the call to this function. 382 * 383 * @param fd The native fd that the ParcelFileDescriptor should adopt. 384 * 385 * @return Returns a new ParcelFileDescriptor holding a FileDescriptor 386 * for the given fd. 387 */ adoptFd(int fd)388 public static ParcelFileDescriptor adoptFd(int fd) { 389 final FileDescriptor fdesc = new FileDescriptor(); 390 fdesc.setInt$(fd); 391 392 return new ParcelFileDescriptor(fdesc); 393 } 394 395 /** 396 * Create a new ParcelFileDescriptor from the specified Socket. The new 397 * ParcelFileDescriptor holds a dup of the original FileDescriptor in 398 * the Socket, so you must still close the Socket as well as the new 399 * ParcelFileDescriptor. 400 * <p> 401 * <strong>WARNING:</strong> Prior to API level 29, this function would not 402 * actually dup the Socket's FileDescriptor, and would take a 403 * reference to the its internal FileDescriptor instead. If the Socket 404 * gets garbage collected before the ParcelFileDescriptor, this may 405 * lead to the ParcelFileDescriptor being unexpectedly closed. To avoid 406 * this, the following pattern can be used: 407 * <pre>{@code 408 * ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket).dup(); 409 * }</pre> 410 * 411 * @param socket The Socket whose FileDescriptor is used to create 412 * a new ParcelFileDescriptor. 413 * 414 * @return A new ParcelFileDescriptor with a duped copy of the 415 * FileDescriptor of the specified Socket. 416 * 417 * @throws UncheckedIOException if {@link #dup(FileDescriptor)} throws IOException. 418 */ fromSocket(Socket socket)419 public static ParcelFileDescriptor fromSocket(Socket socket) { 420 FileDescriptor fd = socket.getFileDescriptor$(); 421 try { 422 return fd != null ? ParcelFileDescriptor.dup(fd) : null; 423 } catch (IOException e) { 424 throw new UncheckedIOException(e); 425 } 426 } 427 428 /** 429 * Create a new ParcelFileDescriptor from the specified DatagramSocket. The 430 * new ParcelFileDescriptor holds a dup of the original FileDescriptor in 431 * the DatagramSocket, so you must still close the DatagramSocket as well 432 * as the new ParcelFileDescriptor. 433 * <p> 434 * <strong>WARNING:</strong> Prior to API level 29, this function would not 435 * actually dup the DatagramSocket's FileDescriptor, and would take a 436 * reference to the its internal FileDescriptor instead. If the DatagramSocket 437 * gets garbage collected before the ParcelFileDescriptor, this may 438 * lead to the ParcelFileDescriptor being unexpectedly closed. To avoid 439 * this, the following pattern can be used: 440 * <pre>{@code 441 * ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(socket).dup(); 442 * }</pre> 443 * 444 * @param datagramSocket The DatagramSocket whose FileDescriptor is used 445 * to create a new ParcelFileDescriptor. 446 * 447 * @return A new ParcelFileDescriptor with a duped copy of the 448 * FileDescriptor of the specified Socket. 449 * 450 * @throws UncheckedIOException if {@link #dup(FileDescriptor)} throws IOException. 451 */ fromDatagramSocket(DatagramSocket datagramSocket)452 public static ParcelFileDescriptor fromDatagramSocket(DatagramSocket datagramSocket) { 453 FileDescriptor fd = datagramSocket.getFileDescriptor$(); 454 try { 455 return fd != null ? ParcelFileDescriptor.dup(fd) : null; 456 } catch (IOException e) { 457 throw new UncheckedIOException(e); 458 } 459 } 460 461 /** 462 * Create two ParcelFileDescriptors structured as a data pipe. The first 463 * ParcelFileDescriptor in the returned array is the read side; the second 464 * is the write side. 465 */ createPipe()466 public static ParcelFileDescriptor[] createPipe() throws IOException { 467 try { 468 final FileDescriptor[] fds = Os.pipe2(ifAtLeastQ(O_CLOEXEC)); 469 return new ParcelFileDescriptor[] { 470 new ParcelFileDescriptor(fds[0]), 471 new ParcelFileDescriptor(fds[1]) }; 472 } catch (ErrnoException e) { 473 throw e.rethrowAsIOException(); 474 } 475 } 476 477 /** 478 * Create two ParcelFileDescriptors structured as a data pipe. The first 479 * ParcelFileDescriptor in the returned array is the read side; the second 480 * is the write side. 481 * <p> 482 * The write end has the ability to deliver an error message through 483 * {@link #closeWithError(String)} which can be handled by the read end 484 * calling {@link #checkError()}, usually after detecting an EOF. 485 * This can also be used to detect remote crashes. 486 */ createReliablePipe()487 public static ParcelFileDescriptor[] createReliablePipe() throws IOException { 488 try { 489 final FileDescriptor[] comm = createCommSocketPair(); 490 final FileDescriptor[] fds = Os.pipe2(ifAtLeastQ(O_CLOEXEC)); 491 return new ParcelFileDescriptor[] { 492 new ParcelFileDescriptor(fds[0], comm[0]), 493 new ParcelFileDescriptor(fds[1], comm[1]) }; 494 } catch (ErrnoException e) { 495 throw e.rethrowAsIOException(); 496 } 497 } 498 499 /** 500 * Create two ParcelFileDescriptors structured as a pair of sockets 501 * connected to each other. The two sockets are indistinguishable. 502 */ createSocketPair()503 public static ParcelFileDescriptor[] createSocketPair() throws IOException { 504 return createSocketPair(SOCK_STREAM); 505 } 506 507 /** 508 * @hide 509 */ createSocketPair(int type)510 public static ParcelFileDescriptor[] createSocketPair(int type) throws IOException { 511 try { 512 final FileDescriptor fd0 = new FileDescriptor(); 513 final FileDescriptor fd1 = new FileDescriptor(); 514 Os.socketpair(AF_UNIX, type | ifAtLeastQ(SOCK_CLOEXEC), 0, fd0, fd1); 515 return new ParcelFileDescriptor[] { 516 new ParcelFileDescriptor(fd0), 517 new ParcelFileDescriptor(fd1) }; 518 } catch (ErrnoException e) { 519 throw e.rethrowAsIOException(); 520 } 521 } 522 523 /** 524 * Create two ParcelFileDescriptors structured as a pair of sockets 525 * connected to each other. The two sockets are indistinguishable. 526 * <p> 527 * Both ends have the ability to deliver an error message through 528 * {@link #closeWithError(String)} which can be detected by the other end 529 * calling {@link #checkError()}, usually after detecting an EOF. 530 * This can also be used to detect remote crashes. 531 */ createReliableSocketPair()532 public static ParcelFileDescriptor[] createReliableSocketPair() throws IOException { 533 return createReliableSocketPair(SOCK_STREAM); 534 } 535 536 /** 537 * @hide 538 */ createReliableSocketPair(int type)539 public static ParcelFileDescriptor[] createReliableSocketPair(int type) throws IOException { 540 try { 541 final FileDescriptor[] comm = createCommSocketPair(); 542 final FileDescriptor fd0 = new FileDescriptor(); 543 final FileDescriptor fd1 = new FileDescriptor(); 544 Os.socketpair(AF_UNIX, type | ifAtLeastQ(SOCK_CLOEXEC), 0, fd0, fd1); 545 return new ParcelFileDescriptor[] { 546 new ParcelFileDescriptor(fd0, comm[0]), 547 new ParcelFileDescriptor(fd1, comm[1]) }; 548 } catch (ErrnoException e) { 549 throw e.rethrowAsIOException(); 550 } 551 } 552 createCommSocketPair()553 private static FileDescriptor[] createCommSocketPair() throws IOException { 554 try { 555 // Use SOCK_SEQPACKET so that we have a guarantee that the status 556 // is written and read atomically as one unit and is not split 557 // across multiple IO operations. 558 final FileDescriptor comm1 = new FileDescriptor(); 559 final FileDescriptor comm2 = new FileDescriptor(); 560 Os.socketpair(AF_UNIX, SOCK_SEQPACKET | ifAtLeastQ(SOCK_CLOEXEC), 0, comm1, comm2); 561 IoUtils.setBlocking(comm1, false); 562 IoUtils.setBlocking(comm2, false); 563 return new FileDescriptor[] { comm1, comm2 }; 564 } catch (ErrnoException e) { 565 throw e.rethrowAsIOException(); 566 } 567 } 568 569 /** 570 * @hide Please use createPipe() or ContentProvider.openPipeHelper(). 571 * Gets a file descriptor for a read-only copy of the given data. 572 * 573 * @param data Data to copy. 574 * @param name Name for the shared memory area that may back the file descriptor. 575 * This is purely informative and may be {@code null}. 576 * @return A ParcelFileDescriptor. 577 * @throws IOException if there is an error while creating the shared memory area. 578 */ 579 @UnsupportedAppUsage 580 @Deprecated fromData(byte[] data, String name)581 public static ParcelFileDescriptor fromData(byte[] data, String name) throws IOException { 582 if (data == null) return null; 583 MemoryFile file = new MemoryFile(name, data.length); 584 if (data.length > 0) { 585 file.writeBytes(data, 0, 0, data.length); 586 } 587 file.deactivate(); 588 FileDescriptor fd = file.getFileDescriptor(); 589 return fd != null ? ParcelFileDescriptor.dup(fd) : null; 590 } 591 592 /** 593 * Converts a string representing a file mode, such as "rw", into a bitmask suitable for use 594 * with {@link #open}. 595 * <p> 596 * @param mode The string representation of the file mode. Can be "r", "w", "wt", "wa", "rw" 597 * or "rwt". 598 * @return A bitmask representing the given file mode. 599 * @throws IllegalArgumentException if the given string does not match a known file mode. 600 */ parseMode(String mode)601 public static int parseMode(String mode) { 602 return FileUtils.translateModePosixToPfd(FileUtils.translateModeStringToPosix(mode)); 603 } 604 605 /** 606 * Return the filesystem path of the real file on disk that is represented 607 * by the given {@link FileDescriptor}. 608 * 609 * @hide 610 */ 611 @TestApi getFile(FileDescriptor fd)612 public static File getFile(FileDescriptor fd) throws IOException { 613 try { 614 final String path = Os.readlink("/proc/self/fd/" + fd.getInt$()); 615 if (OsConstants.S_ISREG(Os.stat(path).st_mode)) { 616 return new File(path); 617 } else { 618 throw new IOException("Not a regular file: " + path); 619 } 620 } catch (ErrnoException e) { 621 throw e.rethrowAsIOException(); 622 } 623 } 624 625 /** 626 * Retrieve the actual FileDescriptor associated with this object. 627 * 628 * @return Returns the FileDescriptor associated with this object. 629 */ getFileDescriptor()630 public FileDescriptor getFileDescriptor() { 631 if (mWrapped != null) { 632 return mWrapped.getFileDescriptor(); 633 } else { 634 return mFd; 635 } 636 } 637 638 /** 639 * Return the total size of the file representing this fd, as determined by 640 * {@code stat()}. Returns -1 if the fd is not a file. 641 */ getStatSize()642 public long getStatSize() { 643 if (mWrapped != null) { 644 return mWrapped.getStatSize(); 645 } else { 646 try { 647 final StructStat st = Os.fstat(mFd); 648 if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) { 649 return st.st_size; 650 } else { 651 return -1; 652 } 653 } catch (ErrnoException e) { 654 Log.w(TAG, "fstat() failed: " + e); 655 return -1; 656 } 657 } 658 } 659 660 /** 661 * This is needed for implementing AssetFileDescriptor.AutoCloseOutputStream, 662 * and I really don't think we want it to be public. 663 * @hide 664 */ 665 @UnsupportedAppUsage seekTo(long pos)666 public long seekTo(long pos) throws IOException { 667 if (mWrapped != null) { 668 return mWrapped.seekTo(pos); 669 } else { 670 try { 671 return Os.lseek(mFd, pos, SEEK_SET); 672 } catch (ErrnoException e) { 673 throw e.rethrowAsIOException(); 674 } 675 } 676 } 677 678 /** 679 * Return the native fd int for this ParcelFileDescriptor. The 680 * ParcelFileDescriptor still owns the fd, and it still must be closed 681 * through this API. 682 * <p> 683 * <strong>WARNING:</strong> Do not call close on the return value of this 684 * function or pass it to a function that assumes ownership of the fd. 685 */ getFd()686 public int getFd() { 687 if (mWrapped != null) { 688 return mWrapped.getFd(); 689 } else { 690 if (mClosed) { 691 throw new IllegalStateException("Already closed"); 692 } 693 return mFd.getInt$(); 694 } 695 } 696 697 /** 698 * Return the native fd int for this ParcelFileDescriptor and detach it from 699 * the object here. You are now responsible for closing the fd in native 700 * code. 701 * <p> 702 * You should not detach when the original creator of the descriptor is 703 * expecting a reliable signal through {@link #close()} or 704 * {@link #closeWithError(String)}. 705 * 706 * @see #canDetectErrors() 707 */ detachFd()708 public int detachFd() { 709 if (mWrapped != null) { 710 return mWrapped.detachFd(); 711 } else { 712 if (mClosed) { 713 throw new IllegalStateException("Already closed"); 714 } 715 int fd = IoUtils.acquireRawFd(mFd); 716 writeCommStatusAndClose(Status.DETACHED, null); 717 mClosed = true; 718 mGuard.close(); 719 releaseResources(); 720 return fd; 721 } 722 } 723 724 /** 725 * Close the ParcelFileDescriptor. This implementation closes the underlying 726 * OS resources allocated to represent this stream. 727 * 728 * @throws IOException 729 * If an error occurs attempting to close this ParcelFileDescriptor. 730 */ 731 @Override close()732 public void close() throws IOException { 733 if (mWrapped != null) { 734 try { 735 mWrapped.close(); 736 } finally { 737 releaseResources(); 738 } 739 } else { 740 closeWithStatus(Status.OK, null); 741 } 742 } 743 744 /** 745 * Close the ParcelFileDescriptor, informing any peer that an error occurred 746 * while processing. If the creator of this descriptor is not observing 747 * errors, it will close normally. 748 * 749 * @param msg describing the error; must not be null. 750 */ closeWithError(String msg)751 public void closeWithError(String msg) throws IOException { 752 if (mWrapped != null) { 753 try { 754 mWrapped.closeWithError(msg); 755 } finally { 756 releaseResources(); 757 } 758 } else { 759 if (msg == null) { 760 throw new IllegalArgumentException("Message must not be null"); 761 } 762 closeWithStatus(Status.ERROR, msg); 763 } 764 } 765 closeWithStatus(int status, String msg)766 private void closeWithStatus(int status, String msg) { 767 if (mClosed) return; 768 mClosed = true; 769 if (mGuard != null) { 770 mGuard.close(); 771 } 772 // Status MUST be sent before closing actual descriptor 773 writeCommStatusAndClose(status, msg); 774 IoUtils.closeQuietly(mFd); 775 releaseResources(); 776 } 777 778 /** 779 * Called when the fd is being closed, for subclasses to release any other resources 780 * associated with it, such as acquired providers. 781 * @hide 782 */ releaseResources()783 public void releaseResources() { 784 } 785 getOrCreateStatusBuffer()786 private byte[] getOrCreateStatusBuffer() { 787 if (mStatusBuf == null) { 788 mStatusBuf = new byte[MAX_STATUS]; 789 } 790 return mStatusBuf; 791 } 792 writeCommStatusAndClose(int status, String msg)793 private void writeCommStatusAndClose(int status, String msg) { 794 if (mCommFd == null) { 795 // Not reliable, or someone already sent status 796 if (msg != null) { 797 Log.w(TAG, "Unable to inform peer: " + msg); 798 } 799 return; 800 } 801 802 if (status == Status.DETACHED) { 803 Log.w(TAG, "Peer expected signal when closed; unable to deliver after detach"); 804 } 805 806 try { 807 if (status == Status.SILENCE) return; 808 809 // Since we're about to close, read off any remote status. It's 810 // okay to remember missing here. 811 mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer()); 812 813 // Skip writing status when other end has already gone away. 814 if (mStatus != null) return; 815 816 try { 817 final byte[] buf = getOrCreateStatusBuffer(); 818 int writePtr = 0; 819 820 Memory.pokeInt(buf, writePtr, status, ByteOrder.BIG_ENDIAN); 821 writePtr += 4; 822 823 if (msg != null) { 824 final byte[] rawMsg = msg.getBytes(); 825 final int len = Math.min(rawMsg.length, buf.length - writePtr); 826 System.arraycopy(rawMsg, 0, buf, writePtr, len); 827 writePtr += len; 828 } 829 830 // Must write the entire status as a single operation. 831 Os.write(mCommFd, buf, 0, writePtr); 832 } catch (ErrnoException e) { 833 // Reporting status is best-effort 834 Log.w(TAG, "Failed to report status: " + e); 835 } catch (InterruptedIOException e) { 836 // Reporting status is best-effort 837 Log.w(TAG, "Failed to report status: " + e); 838 } 839 840 } finally { 841 IoUtils.closeQuietly(mCommFd); 842 mCommFd = null; 843 } 844 } 845 readCommStatus(FileDescriptor comm, byte[] buf)846 private static Status readCommStatus(FileDescriptor comm, byte[] buf) { 847 try { 848 // Must read the entire status as a single operation. 849 final int n = Os.read(comm, buf, 0, buf.length); 850 if (n == 0) { 851 // EOF means they're dead 852 return new Status(Status.DEAD); 853 } else { 854 final int status = Memory.peekInt(buf, 0, ByteOrder.BIG_ENDIAN); 855 if (status == Status.ERROR) { 856 final String msg = new String(buf, 4, n - 4); 857 return new Status(status, msg); 858 } 859 return new Status(status); 860 } 861 } catch (ErrnoException e) { 862 if (e.errno == OsConstants.EAGAIN) { 863 // Remote is still alive, but no status written yet 864 return null; 865 } else { 866 Log.d(TAG, "Failed to read status; assuming dead: " + e); 867 return new Status(Status.DEAD); 868 } 869 } catch (InterruptedIOException e) { 870 Log.d(TAG, "Failed to read status; assuming dead: " + e); 871 return new Status(Status.DEAD); 872 } 873 } 874 875 /** 876 * Indicates if this ParcelFileDescriptor can communicate and detect remote 877 * errors/crashes. 878 * 879 * @see #checkError() 880 */ canDetectErrors()881 public boolean canDetectErrors() { 882 if (mWrapped != null) { 883 return mWrapped.canDetectErrors(); 884 } else { 885 return mCommFd != null; 886 } 887 } 888 889 /** 890 * Detect and throw if the other end of a pipe or socket pair encountered an 891 * error or crashed. This allows a reader to distinguish between a valid EOF 892 * and an error/crash. 893 * <p> 894 * If this ParcelFileDescriptor is unable to detect remote errors, it will 895 * return silently. 896 * 897 * @throws IOException for normal errors. 898 * @throws FileDescriptorDetachedException 899 * if the remote side called {@link #detachFd()}. Once detached, the remote 900 * side is unable to communicate any errors through 901 * {@link #closeWithError(String)}. 902 * @see #canDetectErrors() 903 */ checkError()904 public void checkError() throws IOException { 905 if (mWrapped != null) { 906 mWrapped.checkError(); 907 } else { 908 if (mStatus == null) { 909 if (mCommFd == null) { 910 Log.w(TAG, "Peer didn't provide a comm channel; unable to check for errors"); 911 return; 912 } 913 914 // Try reading status; it might be null if nothing written yet. 915 // Either way, we keep comm open to write our status later. 916 mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer()); 917 } 918 919 if (mStatus == null || mStatus.status == Status.OK) { 920 // No status yet, or everything is peachy! 921 return; 922 } else { 923 throw mStatus.asIOException(); 924 } 925 } 926 } 927 928 /** 929 * An InputStream you can create on a ParcelFileDescriptor, which will 930 * take care of calling {@link ParcelFileDescriptor#close 931 * ParcelFileDescriptor.close()} for you when the stream is closed. 932 */ 933 public static class AutoCloseInputStream extends FileInputStream { 934 private final ParcelFileDescriptor mPfd; 935 AutoCloseInputStream(ParcelFileDescriptor pfd)936 public AutoCloseInputStream(ParcelFileDescriptor pfd) { 937 super(pfd.getFileDescriptor()); 938 mPfd = pfd; 939 } 940 941 @Override close()942 public void close() throws IOException { 943 try { 944 super.close(); 945 } finally { 946 mPfd.close(); 947 } 948 } 949 950 @Override read()951 public int read() throws IOException { 952 final int result = super.read(); 953 if (result == -1 && mPfd.canDetectErrors()) { 954 // Check for errors only on EOF, to minimize overhead. 955 mPfd.checkError(); 956 } 957 return result; 958 } 959 960 @Override read(byte[] b)961 public int read(byte[] b) throws IOException { 962 final int result = super.read(b); 963 if (result == -1 && mPfd.canDetectErrors()) { 964 mPfd.checkError(); 965 } 966 return result; 967 } 968 969 @Override read(byte[] b, int off, int len)970 public int read(byte[] b, int off, int len) throws IOException { 971 final int result = super.read(b, off, len); 972 if (result == -1 && mPfd.canDetectErrors()) { 973 mPfd.checkError(); 974 } 975 return result; 976 } 977 } 978 979 /** 980 * An OutputStream you can create on a ParcelFileDescriptor, which will 981 * take care of calling {@link ParcelFileDescriptor#close 982 * ParcelFileDescriptor.close()} for you when the stream is closed. 983 */ 984 public static class AutoCloseOutputStream extends FileOutputStream { 985 private final ParcelFileDescriptor mPfd; 986 AutoCloseOutputStream(ParcelFileDescriptor pfd)987 public AutoCloseOutputStream(ParcelFileDescriptor pfd) { 988 super(pfd.getFileDescriptor()); 989 mPfd = pfd; 990 } 991 992 @Override close()993 public void close() throws IOException { 994 try { 995 super.close(); 996 } finally { 997 mPfd.close(); 998 } 999 } 1000 } 1001 1002 @Override toString()1003 public String toString() { 1004 if (mWrapped != null) { 1005 return mWrapped.toString(); 1006 } else { 1007 return "{ParcelFileDescriptor: " + mFd + "}"; 1008 } 1009 } 1010 1011 @Override finalize()1012 protected void finalize() throws Throwable { 1013 if (mWrapped != null) { 1014 releaseResources(); 1015 } 1016 if (mGuard != null) { 1017 mGuard.warnIfOpen(); 1018 } 1019 try { 1020 if (!mClosed) { 1021 closeWithStatus(Status.LEAKED, null); 1022 } 1023 } finally { 1024 super.finalize(); 1025 } 1026 } 1027 1028 @Override describeContents()1029 public int describeContents() { 1030 if (mWrapped != null) { 1031 return mWrapped.describeContents(); 1032 } else { 1033 return Parcelable.CONTENTS_FILE_DESCRIPTOR; 1034 } 1035 } 1036 1037 /** 1038 * {@inheritDoc} 1039 * If {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set in flags, 1040 * the file descriptor will be closed after a copy is written to the Parcel. 1041 */ 1042 @Override writeToParcel(Parcel out, int flags)1043 public void writeToParcel(Parcel out, int flags) { 1044 if (mWrapped != null) { 1045 try { 1046 mWrapped.writeToParcel(out, flags); 1047 } finally { 1048 releaseResources(); 1049 } 1050 } else { 1051 if (mCommFd != null) { 1052 out.writeInt(1); 1053 out.writeFileDescriptor(mFd); 1054 out.writeFileDescriptor(mCommFd); 1055 } else { 1056 out.writeInt(0); 1057 out.writeFileDescriptor(mFd); 1058 } 1059 if ((flags & PARCELABLE_WRITE_RETURN_VALUE) != 0 && !mClosed) { 1060 // Not a real close, so emit no status 1061 closeWithStatus(Status.SILENCE, null); 1062 } 1063 } 1064 } 1065 1066 public static final @android.annotation.NonNull Parcelable.Creator<ParcelFileDescriptor> CREATOR 1067 = new Parcelable.Creator<ParcelFileDescriptor>() { 1068 @Override 1069 public ParcelFileDescriptor createFromParcel(Parcel in) { 1070 int hasCommChannel = in.readInt(); 1071 final FileDescriptor fd = in.readRawFileDescriptor(); 1072 FileDescriptor commChannel = null; 1073 if (hasCommChannel != 0) { 1074 commChannel = in.readRawFileDescriptor(); 1075 } 1076 return new ParcelFileDescriptor(fd, commChannel); 1077 } 1078 1079 @Override 1080 public ParcelFileDescriptor[] newArray(int size) { 1081 return new ParcelFileDescriptor[size]; 1082 } 1083 }; 1084 1085 /** 1086 * Callback indicating that a ParcelFileDescriptor has been closed. 1087 */ 1088 public interface OnCloseListener { 1089 /** 1090 * Event indicating the ParcelFileDescriptor to which this listener was 1091 * attached has been closed. 1092 * 1093 * @param e error state, or {@code null} if closed cleanly. 1094 * If the close event was the result of 1095 * {@link ParcelFileDescriptor#detachFd()}, this will be a 1096 * {@link FileDescriptorDetachedException}. After detach the 1097 * remote side may continue reading/writing to the underlying 1098 * {@link FileDescriptor}, but they can no longer deliver 1099 * reliable close/error events. 1100 */ onClose(IOException e)1101 public void onClose(IOException e); 1102 } 1103 1104 /** 1105 * Exception that indicates that the file descriptor was detached. 1106 */ 1107 public static class FileDescriptorDetachedException extends IOException { 1108 1109 private static final long serialVersionUID = 0xDe7ac4edFdL; 1110 FileDescriptorDetachedException()1111 public FileDescriptorDetachedException() { 1112 super("Remote side is detached"); 1113 } 1114 } 1115 1116 /** 1117 * Internal class representing a remote status read by 1118 * {@link ParcelFileDescriptor#readCommStatus(FileDescriptor, byte[])}. 1119 * 1120 * Warning: this must be kept in sync with ParcelFileDescriptorStatus at 1121 * frameworks/native/libs/binder/Parcel.cpp 1122 */ 1123 private static class Status { 1124 /** Special value indicating remote side died. */ 1125 public static final int DEAD = -2; 1126 /** Special value indicating no status should be written. */ 1127 public static final int SILENCE = -1; 1128 1129 /** Remote reported that everything went better than expected. */ 1130 public static final int OK = 0; 1131 /** Remote reported error; length and message follow. */ 1132 public static final int ERROR = 1; 1133 /** Remote reported {@link #detachFd()} and went rogue. */ 1134 public static final int DETACHED = 2; 1135 /** Remote reported their object was finalized. */ 1136 public static final int LEAKED = 3; 1137 1138 public final int status; 1139 public final String msg; 1140 Status(int status)1141 public Status(int status) { 1142 this(status, null); 1143 } 1144 Status(int status, String msg)1145 public Status(int status, String msg) { 1146 this.status = status; 1147 this.msg = msg; 1148 } 1149 asIOException()1150 public IOException asIOException() { 1151 switch (status) { 1152 case DEAD: 1153 return new IOException("Remote side is dead"); 1154 case OK: 1155 return null; 1156 case ERROR: 1157 return new IOException("Remote error: " + msg); 1158 case DETACHED: 1159 return new FileDescriptorDetachedException(); 1160 case LEAKED: 1161 return new IOException("Remote side was leaked"); 1162 default: 1163 return new IOException("Unknown status: " + status); 1164 } 1165 } 1166 1167 @Override toString()1168 public String toString() { 1169 return "{" + status + ": " + msg + "}"; 1170 } 1171 } 1172 isAtLeastQ()1173 private static boolean isAtLeastQ() { 1174 return (VMRuntime.getRuntime().getTargetSdkVersion() >= Build.VERSION_CODES.Q); 1175 } 1176 ifAtLeastQ(int value)1177 private static int ifAtLeastQ(int value) { 1178 return isAtLeastQ() ? value : 0; 1179 } 1180 } 1181