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.compat.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 try { 585 if (data.length > 0) { 586 file.writeBytes(data, 0, 0, data.length); 587 } 588 file.deactivate(); 589 FileDescriptor fd = file.getFileDescriptor(); 590 return fd != null ? ParcelFileDescriptor.dup(fd) : null; 591 } finally { 592 file.close(); 593 } 594 } 595 596 /** 597 * Converts a string representing a file mode, such as "rw", into a bitmask suitable for use 598 * with {@link #open}. 599 * <p> 600 * @param mode The string representation of the file mode. Can be "r", "w", "wt", "wa", "rw" 601 * or "rwt". 602 * @return A bitmask representing the given file mode. 603 * @throws IllegalArgumentException if the given string does not match a known file mode. 604 */ parseMode(String mode)605 public static int parseMode(String mode) { 606 return FileUtils.translateModePosixToPfd(FileUtils.translateModeStringToPosix(mode)); 607 } 608 609 /** 610 * Return the filesystem path of the real file on disk that is represented 611 * by the given {@link FileDescriptor}. 612 * 613 * @hide 614 */ 615 @TestApi getFile(FileDescriptor fd)616 public static File getFile(FileDescriptor fd) throws IOException { 617 try { 618 final String path = Os.readlink("/proc/self/fd/" + fd.getInt$()); 619 if (OsConstants.S_ISREG(Os.stat(path).st_mode)) { 620 return new File(path); 621 } else { 622 throw new IOException("Not a regular file: " + path); 623 } 624 } catch (ErrnoException e) { 625 throw e.rethrowAsIOException(); 626 } 627 } 628 629 /** 630 * Retrieve the actual FileDescriptor associated with this object. 631 * 632 * @return Returns the FileDescriptor associated with this object. 633 */ getFileDescriptor()634 public FileDescriptor getFileDescriptor() { 635 if (mWrapped != null) { 636 return mWrapped.getFileDescriptor(); 637 } else { 638 return mFd; 639 } 640 } 641 642 /** 643 * Return the total size of the file representing this fd, as determined by 644 * {@code stat()}. Returns -1 if the fd is not a file. 645 */ getStatSize()646 public long getStatSize() { 647 if (mWrapped != null) { 648 return mWrapped.getStatSize(); 649 } else { 650 try { 651 final StructStat st = Os.fstat(mFd); 652 if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) { 653 return st.st_size; 654 } else { 655 return -1; 656 } 657 } catch (ErrnoException e) { 658 Log.w(TAG, "fstat() failed: " + e); 659 return -1; 660 } 661 } 662 } 663 664 /** 665 * This is needed for implementing AssetFileDescriptor.AutoCloseOutputStream, 666 * and I really don't think we want it to be public. 667 * @hide 668 */ 669 @UnsupportedAppUsage seekTo(long pos)670 public long seekTo(long pos) throws IOException { 671 if (mWrapped != null) { 672 return mWrapped.seekTo(pos); 673 } else { 674 try { 675 return Os.lseek(mFd, pos, SEEK_SET); 676 } catch (ErrnoException e) { 677 throw e.rethrowAsIOException(); 678 } 679 } 680 } 681 682 /** 683 * Return the native fd int for this ParcelFileDescriptor. The 684 * ParcelFileDescriptor still owns the fd, and it still must be closed 685 * through this API. 686 * <p> 687 * <strong>WARNING:</strong> Do not call close on the return value of this 688 * function or pass it to a function that assumes ownership of the fd. 689 */ getFd()690 public int getFd() { 691 if (mWrapped != null) { 692 return mWrapped.getFd(); 693 } else { 694 if (mClosed) { 695 throw new IllegalStateException("Already closed"); 696 } 697 return mFd.getInt$(); 698 } 699 } 700 701 /** 702 * Return the native fd int for this ParcelFileDescriptor and detach it from 703 * the object here. You are now responsible for closing the fd in native 704 * code. 705 * <p> 706 * You should not detach when the original creator of the descriptor is 707 * expecting a reliable signal through {@link #close()} or 708 * {@link #closeWithError(String)}. 709 * 710 * @see #canDetectErrors() 711 */ detachFd()712 public int detachFd() { 713 if (mWrapped != null) { 714 return mWrapped.detachFd(); 715 } else { 716 if (mClosed) { 717 throw new IllegalStateException("Already closed"); 718 } 719 int fd = IoUtils.acquireRawFd(mFd); 720 writeCommStatusAndClose(Status.DETACHED, null); 721 mClosed = true; 722 mGuard.close(); 723 releaseResources(); 724 return fd; 725 } 726 } 727 728 /** 729 * Close the ParcelFileDescriptor. This implementation closes the underlying 730 * OS resources allocated to represent this stream. 731 * 732 * @throws IOException 733 * If an error occurs attempting to close this ParcelFileDescriptor. 734 */ 735 @Override close()736 public void close() throws IOException { 737 if (mWrapped != null) { 738 try { 739 mWrapped.close(); 740 } finally { 741 releaseResources(); 742 } 743 } else { 744 closeWithStatus(Status.OK, null); 745 } 746 } 747 748 /** 749 * Close the ParcelFileDescriptor, informing any peer that an error occurred 750 * while processing. If the creator of this descriptor is not observing 751 * errors, it will close normally. 752 * 753 * @param msg describing the error; must not be null. 754 */ closeWithError(String msg)755 public void closeWithError(String msg) throws IOException { 756 if (mWrapped != null) { 757 try { 758 mWrapped.closeWithError(msg); 759 } finally { 760 releaseResources(); 761 } 762 } else { 763 if (msg == null) { 764 throw new IllegalArgumentException("Message must not be null"); 765 } 766 closeWithStatus(Status.ERROR, msg); 767 } 768 } 769 closeWithStatus(int status, String msg)770 private void closeWithStatus(int status, String msg) { 771 if (mClosed) return; 772 mClosed = true; 773 if (mGuard != null) { 774 mGuard.close(); 775 } 776 // Status MUST be sent before closing actual descriptor 777 writeCommStatusAndClose(status, msg); 778 IoUtils.closeQuietly(mFd); 779 releaseResources(); 780 } 781 782 /** 783 * Called when the fd is being closed, for subclasses to release any other resources 784 * associated with it, such as acquired providers. 785 * @hide 786 */ releaseResources()787 public void releaseResources() { 788 } 789 getOrCreateStatusBuffer()790 private byte[] getOrCreateStatusBuffer() { 791 if (mStatusBuf == null) { 792 mStatusBuf = new byte[MAX_STATUS]; 793 } 794 return mStatusBuf; 795 } 796 writeCommStatusAndClose(int status, String msg)797 private void writeCommStatusAndClose(int status, String msg) { 798 if (mCommFd == null) { 799 // Not reliable, or someone already sent status 800 if (msg != null) { 801 Log.w(TAG, "Unable to inform peer: " + msg); 802 } 803 return; 804 } 805 806 if (status == Status.DETACHED) { 807 Log.w(TAG, "Peer expected signal when closed; unable to deliver after detach"); 808 } 809 810 try { 811 if (status == Status.SILENCE) return; 812 813 // Since we're about to close, read off any remote status. It's 814 // okay to remember missing here. 815 mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer()); 816 817 // Skip writing status when other end has already gone away. 818 if (mStatus != null) return; 819 820 try { 821 final byte[] buf = getOrCreateStatusBuffer(); 822 int writePtr = 0; 823 824 Memory.pokeInt(buf, writePtr, status, ByteOrder.BIG_ENDIAN); 825 writePtr += 4; 826 827 if (msg != null) { 828 final byte[] rawMsg = msg.getBytes(); 829 final int len = Math.min(rawMsg.length, buf.length - writePtr); 830 System.arraycopy(rawMsg, 0, buf, writePtr, len); 831 writePtr += len; 832 } 833 834 // Must write the entire status as a single operation. 835 Os.write(mCommFd, buf, 0, writePtr); 836 } catch (ErrnoException e) { 837 // Reporting status is best-effort 838 Log.w(TAG, "Failed to report status: " + e); 839 } catch (InterruptedIOException e) { 840 // Reporting status is best-effort 841 Log.w(TAG, "Failed to report status: " + e); 842 } 843 844 } finally { 845 IoUtils.closeQuietly(mCommFd); 846 mCommFd = null; 847 } 848 } 849 readCommStatus(FileDescriptor comm, byte[] buf)850 private static Status readCommStatus(FileDescriptor comm, byte[] buf) { 851 try { 852 // Must read the entire status as a single operation. 853 final int n = Os.read(comm, buf, 0, buf.length); 854 if (n == 0) { 855 // EOF means they're dead 856 return new Status(Status.DEAD); 857 } else { 858 final int status = Memory.peekInt(buf, 0, ByteOrder.BIG_ENDIAN); 859 if (status == Status.ERROR) { 860 final String msg = new String(buf, 4, n - 4); 861 return new Status(status, msg); 862 } 863 return new Status(status); 864 } 865 } catch (ErrnoException e) { 866 if (e.errno == OsConstants.EAGAIN) { 867 // Remote is still alive, but no status written yet 868 return null; 869 } else { 870 Log.d(TAG, "Failed to read status; assuming dead: " + e); 871 return new Status(Status.DEAD); 872 } 873 } catch (InterruptedIOException e) { 874 Log.d(TAG, "Failed to read status; assuming dead: " + e); 875 return new Status(Status.DEAD); 876 } 877 } 878 879 /** 880 * Indicates if this ParcelFileDescriptor can communicate and detect remote 881 * errors/crashes. 882 * 883 * @see #checkError() 884 */ canDetectErrors()885 public boolean canDetectErrors() { 886 if (mWrapped != null) { 887 return mWrapped.canDetectErrors(); 888 } else { 889 return mCommFd != null; 890 } 891 } 892 893 /** 894 * Detect and throw if the other end of a pipe or socket pair encountered an 895 * error or crashed. This allows a reader to distinguish between a valid EOF 896 * and an error/crash. 897 * <p> 898 * If this ParcelFileDescriptor is unable to detect remote errors, it will 899 * return silently. 900 * 901 * @throws IOException for normal errors. 902 * @throws FileDescriptorDetachedException 903 * if the remote side called {@link #detachFd()}. Once detached, the remote 904 * side is unable to communicate any errors through 905 * {@link #closeWithError(String)}. 906 * @see #canDetectErrors() 907 */ checkError()908 public void checkError() throws IOException { 909 if (mWrapped != null) { 910 mWrapped.checkError(); 911 } else { 912 if (mStatus == null) { 913 if (mCommFd == null) { 914 Log.w(TAG, "Peer didn't provide a comm channel; unable to check for errors"); 915 return; 916 } 917 918 // Try reading status; it might be null if nothing written yet. 919 // Either way, we keep comm open to write our status later. 920 mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer()); 921 } 922 923 if (mStatus == null || mStatus.status == Status.OK) { 924 // No status yet, or everything is peachy! 925 return; 926 } else { 927 throw mStatus.asIOException(); 928 } 929 } 930 } 931 932 /** 933 * An InputStream you can create on a ParcelFileDescriptor, which will 934 * take care of calling {@link ParcelFileDescriptor#close 935 * ParcelFileDescriptor.close()} for you when the stream is closed. 936 */ 937 public static class AutoCloseInputStream extends FileInputStream { 938 private final ParcelFileDescriptor mPfd; 939 AutoCloseInputStream(ParcelFileDescriptor pfd)940 public AutoCloseInputStream(ParcelFileDescriptor pfd) { 941 super(pfd.getFileDescriptor()); 942 mPfd = pfd; 943 } 944 945 @Override close()946 public void close() throws IOException { 947 try { 948 super.close(); 949 } finally { 950 mPfd.close(); 951 } 952 } 953 954 @Override read()955 public int read() throws IOException { 956 final int result = super.read(); 957 if (result == -1 && mPfd.canDetectErrors()) { 958 // Check for errors only on EOF, to minimize overhead. 959 mPfd.checkError(); 960 } 961 return result; 962 } 963 964 @Override read(byte[] b)965 public int read(byte[] b) throws IOException { 966 final int result = super.read(b); 967 if (result == -1 && mPfd.canDetectErrors()) { 968 mPfd.checkError(); 969 } 970 return result; 971 } 972 973 @Override read(byte[] b, int off, int len)974 public int read(byte[] b, int off, int len) throws IOException { 975 final int result = super.read(b, off, len); 976 if (result == -1 && mPfd.canDetectErrors()) { 977 mPfd.checkError(); 978 } 979 return result; 980 } 981 } 982 983 /** 984 * An OutputStream you can create on a ParcelFileDescriptor, which will 985 * take care of calling {@link ParcelFileDescriptor#close 986 * ParcelFileDescriptor.close()} for you when the stream is closed. 987 */ 988 public static class AutoCloseOutputStream extends FileOutputStream { 989 private final ParcelFileDescriptor mPfd; 990 AutoCloseOutputStream(ParcelFileDescriptor pfd)991 public AutoCloseOutputStream(ParcelFileDescriptor pfd) { 992 super(pfd.getFileDescriptor()); 993 mPfd = pfd; 994 } 995 996 @Override close()997 public void close() throws IOException { 998 try { 999 super.close(); 1000 } finally { 1001 mPfd.close(); 1002 } 1003 } 1004 } 1005 1006 @Override toString()1007 public String toString() { 1008 if (mWrapped != null) { 1009 return mWrapped.toString(); 1010 } else { 1011 return "{ParcelFileDescriptor: " + mFd + "}"; 1012 } 1013 } 1014 1015 @Override finalize()1016 protected void finalize() throws Throwable { 1017 if (mWrapped != null) { 1018 releaseResources(); 1019 } 1020 if (mGuard != null) { 1021 mGuard.warnIfOpen(); 1022 } 1023 try { 1024 if (!mClosed) { 1025 closeWithStatus(Status.LEAKED, null); 1026 } 1027 } finally { 1028 super.finalize(); 1029 } 1030 } 1031 1032 @Override describeContents()1033 public int describeContents() { 1034 if (mWrapped != null) { 1035 return mWrapped.describeContents(); 1036 } else { 1037 return Parcelable.CONTENTS_FILE_DESCRIPTOR; 1038 } 1039 } 1040 1041 /** 1042 * {@inheritDoc} 1043 * If {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set in flags, 1044 * the file descriptor will be closed after a copy is written to the Parcel. 1045 */ 1046 @Override writeToParcel(Parcel out, int flags)1047 public void writeToParcel(Parcel out, int flags) { 1048 if (mWrapped != null) { 1049 try { 1050 mWrapped.writeToParcel(out, flags); 1051 } finally { 1052 releaseResources(); 1053 } 1054 } else { 1055 if (mCommFd != null) { 1056 out.writeInt(1); 1057 out.writeFileDescriptor(mFd); 1058 out.writeFileDescriptor(mCommFd); 1059 } else { 1060 out.writeInt(0); 1061 out.writeFileDescriptor(mFd); 1062 } 1063 if ((flags & PARCELABLE_WRITE_RETURN_VALUE) != 0 && !mClosed) { 1064 // Not a real close, so emit no status 1065 closeWithStatus(Status.SILENCE, null); 1066 } 1067 } 1068 } 1069 1070 public static final @android.annotation.NonNull Parcelable.Creator<ParcelFileDescriptor> CREATOR 1071 = new Parcelable.Creator<ParcelFileDescriptor>() { 1072 @Override 1073 public ParcelFileDescriptor createFromParcel(Parcel in) { 1074 int hasCommChannel = in.readInt(); 1075 final FileDescriptor fd = in.readRawFileDescriptor(); 1076 FileDescriptor commChannel = null; 1077 if (hasCommChannel != 0) { 1078 commChannel = in.readRawFileDescriptor(); 1079 } 1080 return new ParcelFileDescriptor(fd, commChannel); 1081 } 1082 1083 @Override 1084 public ParcelFileDescriptor[] newArray(int size) { 1085 return new ParcelFileDescriptor[size]; 1086 } 1087 }; 1088 1089 /** 1090 * Callback indicating that a ParcelFileDescriptor has been closed. 1091 */ 1092 public interface OnCloseListener { 1093 /** 1094 * Event indicating the ParcelFileDescriptor to which this listener was 1095 * attached has been closed. 1096 * 1097 * @param e error state, or {@code null} if closed cleanly. 1098 * If the close event was the result of 1099 * {@link ParcelFileDescriptor#detachFd()}, this will be a 1100 * {@link FileDescriptorDetachedException}. After detach the 1101 * remote side may continue reading/writing to the underlying 1102 * {@link FileDescriptor}, but they can no longer deliver 1103 * reliable close/error events. 1104 */ onClose(IOException e)1105 public void onClose(IOException e); 1106 } 1107 1108 /** 1109 * Exception that indicates that the file descriptor was detached. 1110 */ 1111 public static class FileDescriptorDetachedException extends IOException { 1112 1113 private static final long serialVersionUID = 0xDe7ac4edFdL; 1114 FileDescriptorDetachedException()1115 public FileDescriptorDetachedException() { 1116 super("Remote side is detached"); 1117 } 1118 } 1119 1120 /** 1121 * Internal class representing a remote status read by 1122 * {@link ParcelFileDescriptor#readCommStatus(FileDescriptor, byte[])}. 1123 * 1124 * Warning: this must be kept in sync with ParcelFileDescriptorStatus at 1125 * frameworks/native/libs/binder/Parcel.cpp 1126 */ 1127 private static class Status { 1128 /** Special value indicating remote side died. */ 1129 public static final int DEAD = -2; 1130 /** Special value indicating no status should be written. */ 1131 public static final int SILENCE = -1; 1132 1133 /** Remote reported that everything went better than expected. */ 1134 public static final int OK = 0; 1135 /** Remote reported error; length and message follow. */ 1136 public static final int ERROR = 1; 1137 /** Remote reported {@link #detachFd()} and went rogue. */ 1138 public static final int DETACHED = 2; 1139 /** Remote reported their object was finalized. */ 1140 public static final int LEAKED = 3; 1141 1142 public final int status; 1143 public final String msg; 1144 Status(int status)1145 public Status(int status) { 1146 this(status, null); 1147 } 1148 Status(int status, String msg)1149 public Status(int status, String msg) { 1150 this.status = status; 1151 this.msg = msg; 1152 } 1153 asIOException()1154 public IOException asIOException() { 1155 switch (status) { 1156 case DEAD: 1157 return new IOException("Remote side is dead"); 1158 case OK: 1159 return null; 1160 case ERROR: 1161 return new IOException("Remote error: " + msg); 1162 case DETACHED: 1163 return new FileDescriptorDetachedException(); 1164 case LEAKED: 1165 return new IOException("Remote side was leaked"); 1166 default: 1167 return new IOException("Unknown status: " + status); 1168 } 1169 } 1170 1171 @Override toString()1172 public String toString() { 1173 return "{" + status + ": " + msg + "}"; 1174 } 1175 } 1176 isAtLeastQ()1177 private static boolean isAtLeastQ() { 1178 return (VMRuntime.getRuntime().getTargetSdkVersion() >= Build.VERSION_CODES.Q); 1179 } 1180 ifAtLeastQ(int value)1181 private static int ifAtLeastQ(int value) { 1182 return isAtLeastQ() ? value : 0; 1183 } 1184 } 1185