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