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