Loading core/java/android/os/ParcelFileDescriptor.java +109 −14 Original line number Diff line number Diff line Loading @@ -40,14 +40,18 @@ import android.content.ContentProvider; import android.content.ContentResolver; import android.net.Uri; import android.os.MessageQueue.OnFileDescriptorEventListener; import android.ravenwood.annotation.RavenwoodKeepWholeClass; import android.ravenwood.annotation.RavenwoodNativeSubstitutionClass; import android.ravenwood.annotation.RavenwoodReplace; import android.ravenwood.annotation.RavenwoodThrow; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; import android.system.StructStat; import android.util.CloseGuard; import android.util.Log; import android.util.Slog; import dalvik.system.CloseGuard; import dalvik.system.VMRuntime; import libcore.io.IoUtils; Loading @@ -70,6 +74,8 @@ import java.nio.ByteOrder; * The FileDescriptor returned by {@link Parcel#readFileDescriptor}, allowing * you to close it when done with it. */ @RavenwoodKeepWholeClass @RavenwoodNativeSubstitutionClass("com.android.hoststubgen.nativesubstitution.ParcelFileDescriptor_host") public class ParcelFileDescriptor implements Parcelable, Closeable { private static final String TAG = "ParcelFileDescriptor"; Loading Loading @@ -197,11 +203,11 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { } mWrapped = null; mFd = fd; IoUtils.setFdOwner(mFd, this); setFdOwner(mFd); mCommFd = commChannel; if (mCommFd != null) { IoUtils.setFdOwner(mCommFd, this); setFdOwner(mCommFd); } mGuard.open("close"); Loading Loading @@ -284,15 +290,17 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { */ // We can't accept a generic Executor here, since we need to use // MessageQueue.addOnFileDescriptorEventListener() @RavenwoodThrow(blockedBy = MessageQueue.class) @SuppressLint("ExecutorRegistration") public static @NonNull ParcelFileDescriptor wrap(@NonNull ParcelFileDescriptor pfd, @NonNull Handler handler, @NonNull OnCloseListener listener) throws IOException { final FileDescriptor original = new FileDescriptor(); original.setInt$(pfd.detachFd()); setFdInt(original, pfd.detachFd()); return fromFd(original, handler, listener); } /** {@hide} */ @RavenwoodThrow(blockedBy = MessageQueue.class) public static ParcelFileDescriptor fromFd(FileDescriptor fd, Handler handler, final OnCloseListener listener) throws IOException { if (handler == null) { Loading @@ -318,7 +326,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { } if (status != null) { queue.removeOnFileDescriptorEventListener(fd); IoUtils.closeQuietly(fd); closeInternal(fd); listener.onClose(status.asIOException()); return 0; } Loading @@ -329,6 +337,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { return pfd; } @RavenwoodReplace private static FileDescriptor openInternal(File file, int mode) throws FileNotFoundException { if ((mode & MODE_WRITE_ONLY) != 0 && (mode & MODE_APPEND) == 0 && (mode & MODE_TRUNCATE) == 0 && ((mode & MODE_READ_ONLY) == 0) Loading @@ -352,17 +361,38 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { } } private static FileDescriptor openInternal$ravenwood(File file, int mode) throws FileNotFoundException { try { return native_open$ravenwood(file, mode); } catch (FileNotFoundException e) { throw e; } catch (IOException e) { throw new FileNotFoundException(e.getMessage()); } } @RavenwoodReplace private static void closeInternal(FileDescriptor fd) { IoUtils.closeQuietly(fd); } private static void closeInternal$ravenwood(FileDescriptor fd) { native_close$ravenwood(fd); } /** * Create a new ParcelFileDescriptor that is a dup of an existing * FileDescriptor. This obeys standard POSIX semantics, where the * new file descriptor shared state such as file position with the * original file descriptor. */ @RavenwoodThrow(reason = "Requires JNI support") public static ParcelFileDescriptor dup(FileDescriptor orig) throws IOException { try { final FileDescriptor fd = new FileDescriptor(); int intfd = Os.fcntlInt(orig, (isAtLeastQ() ? F_DUPFD_CLOEXEC : F_DUPFD), 0); fd.setInt$(intfd); setFdInt(fd, intfd); return new ParcelFileDescriptor(fd); } catch (ErrnoException e) { throw e.rethrowAsIOException(); Loading @@ -375,6 +405,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * new file descriptor shared state such as file position with the * original file descriptor. */ @RavenwoodThrow(reason = "Requires JNI support") public ParcelFileDescriptor dup() throws IOException { if (mWrapped != null) { return mWrapped.dup(); Loading @@ -393,14 +424,15 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * @return Returns a new ParcelFileDescriptor holding a FileDescriptor * for a dup of the given fd. */ @RavenwoodThrow(reason = "Requires JNI support") public static ParcelFileDescriptor fromFd(int fd) throws IOException { final FileDescriptor original = new FileDescriptor(); original.setInt$(fd); setFdInt(original, fd); try { final FileDescriptor dup = new FileDescriptor(); int intfd = Os.fcntlInt(original, (isAtLeastQ() ? F_DUPFD_CLOEXEC : F_DUPFD), 0); dup.setInt$(intfd); setFdInt(dup, intfd); return new ParcelFileDescriptor(dup); } catch (ErrnoException e) { throw e.rethrowAsIOException(); Loading @@ -423,7 +455,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { */ public static ParcelFileDescriptor adoptFd(int fd) { final FileDescriptor fdesc = new FileDescriptor(); fdesc.setInt$(fd); setFdInt(fdesc, fd); return new ParcelFileDescriptor(fdesc); } Loading Loading @@ -452,6 +484,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * * @throws UncheckedIOException if {@link #dup(FileDescriptor)} throws IOException. */ @RavenwoodThrow(reason = "Requires JNI support") public static ParcelFileDescriptor fromSocket(Socket socket) { FileDescriptor fd = socket.getFileDescriptor$(); try { Loading Loading @@ -485,6 +518,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * * @throws UncheckedIOException if {@link #dup(FileDescriptor)} throws IOException. */ @RavenwoodThrow(reason = "Requires JNI support") public static ParcelFileDescriptor fromDatagramSocket(DatagramSocket datagramSocket) { FileDescriptor fd = datagramSocket.getFileDescriptor$(); try { Loading @@ -499,6 +533,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * ParcelFileDescriptor in the returned array is the read side; the second * is the write side. */ @RavenwoodThrow(reason = "Requires JNI support") public static ParcelFileDescriptor[] createPipe() throws IOException { try { final FileDescriptor[] fds = Os.pipe2(ifAtLeastQ(O_CLOEXEC)); Loading @@ -520,6 +555,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * calling {@link #checkError()}, usually after detecting an EOF. * This can also be used to detect remote crashes. */ @RavenwoodThrow(reason = "Requires JNI support") public static ParcelFileDescriptor[] createReliablePipe() throws IOException { try { final FileDescriptor[] comm = createCommSocketPair(); Loading @@ -536,6 +572,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * Create two ParcelFileDescriptors structured as a pair of sockets * connected to each other. The two sockets are indistinguishable. */ @RavenwoodThrow(reason = "Requires JNI support") public static ParcelFileDescriptor[] createSocketPair() throws IOException { return createSocketPair(SOCK_STREAM); } Loading @@ -543,6 +580,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { /** * @hide */ @RavenwoodThrow(reason = "Requires JNI support") public static ParcelFileDescriptor[] createSocketPair(int type) throws IOException { try { final FileDescriptor fd0 = new FileDescriptor(); Loading @@ -565,6 +603,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * calling {@link #checkError()}, usually after detecting an EOF. * This can also be used to detect remote crashes. */ @RavenwoodThrow(reason = "Requires JNI support") public static ParcelFileDescriptor[] createReliableSocketPair() throws IOException { return createReliableSocketPair(SOCK_STREAM); } Loading @@ -572,6 +611,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { /** * @hide */ @RavenwoodThrow(reason = "Requires JNI support") public static ParcelFileDescriptor[] createReliableSocketPair(int type) throws IOException { try { final FileDescriptor[] comm = createCommSocketPair(); Loading @@ -586,6 +626,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { } } @RavenwoodThrow(reason = "Requires JNI support") private static FileDescriptor[] createCommSocketPair() throws IOException { try { // Use SOCK_SEQPACKET so that we have a guarantee that the status Loading Loading @@ -614,6 +655,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { */ @UnsupportedAppUsage @Deprecated @RavenwoodThrow(reason = "Requires JNI support") public static ParcelFileDescriptor fromData(byte[] data, String name) throws IOException { if (data == null) return null; MemoryFile file = new MemoryFile(name, data.length); Loading Loading @@ -669,9 +711,10 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * @hide */ @TestApi @RavenwoodThrow(reason = "Requires kernel support") public static File getFile(FileDescriptor fd) throws IOException { try { final String path = Os.readlink("/proc/self/fd/" + fd.getInt$()); final String path = Os.readlink("/proc/self/fd/" + getFdInt(fd)); if (OsConstants.S_ISREG(Os.stat(path).st_mode) || OsConstants.S_ISCHR(Os.stat(path).st_mode)) { return new File(path); Loading Loading @@ -700,6 +743,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * Return the total size of the file representing this fd, as determined by * {@code stat()}. Returns -1 if the fd is not a file. */ @RavenwoodThrow(reason = "Requires JNI support") public long getStatSize() { if (mWrapped != null) { return mWrapped.getStatSize(); Loading @@ -724,6 +768,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * @hide */ @UnsupportedAppUsage @RavenwoodThrow(reason = "Requires JNI support") public long seekTo(long pos) throws IOException { if (mWrapped != null) { return mWrapped.seekTo(pos); Loading Loading @@ -751,7 +796,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { if (mClosed) { throw new IllegalStateException("Already closed"); } return mFd.getInt$(); return getFdInt(mFd); } } Loading @@ -773,7 +818,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { if (mClosed) { throw new IllegalStateException("Already closed"); } int fd = IoUtils.acquireRawFd(mFd); int fd = acquireRawFd(mFd); writeCommStatusAndClose(Status.DETACHED, null); mClosed = true; mGuard.close(); Loading Loading @@ -832,7 +877,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { } // Status MUST be sent before closing actual descriptor writeCommStatusAndClose(status, msg); IoUtils.closeQuietly(mFd); closeInternal(mFd); releaseResources(); } Loading Loading @@ -899,7 +944,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { } } finally { IoUtils.closeQuietly(mCommFd); closeInternal(mCommFd); mCommFd = null; } } Loading Loading @@ -991,6 +1036,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * take care of calling {@link ParcelFileDescriptor#close * ParcelFileDescriptor.close()} for you when the stream is closed. */ @RavenwoodKeepWholeClass public static class AutoCloseInputStream extends FileInputStream { private final ParcelFileDescriptor mPfd; Loading Loading @@ -1042,6 +1088,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * take care of calling {@link ParcelFileDescriptor#close * ParcelFileDescriptor.close()} for you when the stream is closed. */ @RavenwoodKeepWholeClass public static class AutoCloseOutputStream extends FileOutputStream { private final ParcelFileDescriptor mPfd; Loading Loading @@ -1232,10 +1279,58 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { } } // These native methods are currently only implemented by Ravenwood, as it's the only // mechanism we have to jump to our RavenwoodNativeSubstitutionClass private static native void native_setFdInt$ravenwood(FileDescriptor fd, int fdInt); private static native int native_getFdInt$ravenwood(FileDescriptor fd); private static native FileDescriptor native_open$ravenwood(File file, int pfdMode) throws IOException; private static native void native_close$ravenwood(FileDescriptor fd); @RavenwoodReplace private static void setFdInt(FileDescriptor fd, int fdInt) { fd.setInt$(fdInt); } private static void setFdInt$ravenwood(FileDescriptor fd, int fdInt) { native_setFdInt$ravenwood(fd, fdInt); } @RavenwoodReplace private static int getFdInt(FileDescriptor fd) { return fd.getInt$(); } private static int getFdInt$ravenwood(FileDescriptor fd) { return native_getFdInt$ravenwood(fd); } @RavenwoodReplace private void setFdOwner(FileDescriptor fd) { IoUtils.setFdOwner(fd, this); } private void setFdOwner$ravenwood(FileDescriptor fd) { // FD owners currently unsupported under Ravenwood; ignored } @RavenwoodReplace private int acquireRawFd(FileDescriptor fd) { return IoUtils.acquireRawFd(fd); } private int acquireRawFd$ravenwood(FileDescriptor fd) { // FD owners currently unsupported under Ravenwood; return FD directly return getFdInt(fd); } @RavenwoodThrow private static boolean isAtLeastQ() { return (VMRuntime.getRuntime().getTargetSdkVersion() >= Build.VERSION_CODES.Q); } @RavenwoodThrow private static int ifAtLeastQ(int value) { return isAtLeastQ() ? value : 0; } Loading core/java/android/util/CloseGuard.java +32 −4 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package android.util; import android.annotation.NonNull; import android.ravenwood.annotation.RavenwoodKeepWholeClass; import android.ravenwood.annotation.RavenwoodReplace; /** * CloseGuard is a mechanism for flagging implicit finalizer cleanup of Loading Loading @@ -108,15 +110,35 @@ import android.annotation.NonNull; * in a method, the call to {@code open} should occur just after * resource acquisition. */ @RavenwoodKeepWholeClass public final class CloseGuard { private final dalvik.system.CloseGuard mImpl; /** * Constructs a new CloseGuard instance. * {@link #open(String)} can be used to set up the instance to warn on failure to close. * * @hide */ public static CloseGuard get() { return new CloseGuard(); } /** * Constructs a new CloseGuard instance. * {@link #open(String)} can be used to set up the instance to warn on failure to close. */ public CloseGuard() { mImpl = dalvik.system.CloseGuard.get(); mImpl = getImpl(); } @RavenwoodReplace private dalvik.system.CloseGuard getImpl() { return dalvik.system.CloseGuard.get(); } private dalvik.system.CloseGuard getImpl$ravenwood() { return null; } /** Loading @@ -127,19 +149,25 @@ public final class CloseGuard { * @throws NullPointerException if closeMethodName is null. */ public void open(@NonNull String closeMethodName) { if (mImpl != null) { mImpl.open(closeMethodName); } } /** Marks this CloseGuard instance as closed to avoid warnings on finalization. */ public void close() { if (mImpl != null) { mImpl.close(); } } /** * Logs a warning if the caller did not properly cleanup by calling an explicit close method * before finalization. */ public void warnIfOpen() { if (mImpl != null) { mImpl.warnIfOpen(); } } } ravenwood/ravenwood-annotation-allowed-classes.txt +4 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ com.android.internal.os.RuntimeInit com.android.internal.power.ModemPowerProfile android.util.AtomicFile android.util.CloseGuard android.util.DataUnit android.util.DayOfMonthCursor android.util.DumpableContainer Loading Loading @@ -68,6 +69,9 @@ android.os.Message android.os.MessageQueue android.os.PackageTagsList android.os.Parcel android.os.ParcelFileDescriptor android.os.ParcelFileDescriptor$AutoCloseInputStream android.os.ParcelFileDescriptor$AutoCloseOutputStream android.os.Parcelable android.os.PowerComponents android.os.Process Loading tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/ParcelFileDescriptor_host.java 0 → 100644 +128 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.hoststubgen.nativesubstitution; import static android.os.ParcelFileDescriptor.MODE_APPEND; import static android.os.ParcelFileDescriptor.MODE_CREATE; import static android.os.ParcelFileDescriptor.MODE_READ_ONLY; import static android.os.ParcelFileDescriptor.MODE_READ_WRITE; import static android.os.ParcelFileDescriptor.MODE_TRUNCATE; import static android.os.ParcelFileDescriptor.MODE_WORLD_READABLE; import static android.os.ParcelFileDescriptor.MODE_WORLD_WRITEABLE; import static android.os.ParcelFileDescriptor.MODE_WRITE_ONLY; import com.android.internal.annotations.GuardedBy; import java.io.File; import java.io.FileDescriptor; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.RandomAccessFile; import java.util.HashMap; import java.util.Map; public class ParcelFileDescriptor_host { /** * Since we don't have a great way to keep an unmanaged {@code FileDescriptor} reference * alive, we keep a strong reference to the {@code RandomAccessFile} we used to open it. This * gives us a way to look up the original parent object when closing later. */ @GuardedBy("sActive") private static final Map<FileDescriptor, RandomAccessFile> sActive = new HashMap<>(); public static void native_setFdInt$ravenwood(FileDescriptor fd, int fdInt) { try { final Object obj = Class.forName("jdk.internal.access.SharedSecrets").getMethod( "getJavaIOFileDescriptorAccess").invoke(null); Class.forName("jdk.internal.access.JavaIOFileDescriptorAccess").getMethod( "set", FileDescriptor.class, int.class).invoke(obj, fd, fdInt); } catch (ReflectiveOperationException e) { throw new RuntimeException("Failed to interact with raw FileDescriptor internals;" + " perhaps JRE has changed?", e); } } public static int native_getFdInt$ravenwood(FileDescriptor fd) { try { final Object obj = Class.forName("jdk.internal.access.SharedSecrets").getMethod( "getJavaIOFileDescriptorAccess").invoke(null); return (int) Class.forName("jdk.internal.access.JavaIOFileDescriptorAccess").getMethod( "get", FileDescriptor.class).invoke(obj, fd); } catch (ReflectiveOperationException e) { throw new RuntimeException("Failed to interact with raw FileDescriptor internals;" + " perhaps JRE has changed?", e); } } public static FileDescriptor native_open$ravenwood(File file, int pfdMode) throws IOException { if ((pfdMode & MODE_CREATE) != 0 && !file.exists()) { throw new FileNotFoundException(); } final String modeString; if ((pfdMode & MODE_READ_WRITE) == MODE_READ_WRITE) { modeString = "rw"; } else if ((pfdMode & MODE_WRITE_ONLY) == MODE_WRITE_ONLY) { modeString = "rw"; } else if ((pfdMode & MODE_READ_ONLY) == MODE_READ_ONLY) { modeString = "r"; } else { throw new IllegalArgumentException(); } final RandomAccessFile raf = new RandomAccessFile(file, modeString); // Now that we have a real file on disk, match requested flags if ((pfdMode & MODE_TRUNCATE) != 0) { raf.setLength(0); } if ((pfdMode & MODE_APPEND) != 0) { raf.seek(raf.length()); } if ((pfdMode & MODE_WORLD_READABLE) != 0) { file.setReadable(true, false); } if ((pfdMode & MODE_WORLD_WRITEABLE) != 0) { file.setWritable(true, false); } final FileDescriptor fd = raf.getFD(); synchronized (sActive) { sActive.put(fd, raf); } return fd; } public static void native_close$ravenwood(FileDescriptor fd) { final RandomAccessFile raf; synchronized (sActive) { raf = sActive.remove(fd); } try { if (raf != null) { raf.close(); } else { // Odd, we don't remember opening this ourselves, but let's release the // underlying resource as requested System.err.println("Closing unknown FileDescriptor: " + fd); new FileOutputStream(fd).close(); } } catch (IOException ignored) { } } } Loading
core/java/android/os/ParcelFileDescriptor.java +109 −14 Original line number Diff line number Diff line Loading @@ -40,14 +40,18 @@ import android.content.ContentProvider; import android.content.ContentResolver; import android.net.Uri; import android.os.MessageQueue.OnFileDescriptorEventListener; import android.ravenwood.annotation.RavenwoodKeepWholeClass; import android.ravenwood.annotation.RavenwoodNativeSubstitutionClass; import android.ravenwood.annotation.RavenwoodReplace; import android.ravenwood.annotation.RavenwoodThrow; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; import android.system.StructStat; import android.util.CloseGuard; import android.util.Log; import android.util.Slog; import dalvik.system.CloseGuard; import dalvik.system.VMRuntime; import libcore.io.IoUtils; Loading @@ -70,6 +74,8 @@ import java.nio.ByteOrder; * The FileDescriptor returned by {@link Parcel#readFileDescriptor}, allowing * you to close it when done with it. */ @RavenwoodKeepWholeClass @RavenwoodNativeSubstitutionClass("com.android.hoststubgen.nativesubstitution.ParcelFileDescriptor_host") public class ParcelFileDescriptor implements Parcelable, Closeable { private static final String TAG = "ParcelFileDescriptor"; Loading Loading @@ -197,11 +203,11 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { } mWrapped = null; mFd = fd; IoUtils.setFdOwner(mFd, this); setFdOwner(mFd); mCommFd = commChannel; if (mCommFd != null) { IoUtils.setFdOwner(mCommFd, this); setFdOwner(mCommFd); } mGuard.open("close"); Loading Loading @@ -284,15 +290,17 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { */ // We can't accept a generic Executor here, since we need to use // MessageQueue.addOnFileDescriptorEventListener() @RavenwoodThrow(blockedBy = MessageQueue.class) @SuppressLint("ExecutorRegistration") public static @NonNull ParcelFileDescriptor wrap(@NonNull ParcelFileDescriptor pfd, @NonNull Handler handler, @NonNull OnCloseListener listener) throws IOException { final FileDescriptor original = new FileDescriptor(); original.setInt$(pfd.detachFd()); setFdInt(original, pfd.detachFd()); return fromFd(original, handler, listener); } /** {@hide} */ @RavenwoodThrow(blockedBy = MessageQueue.class) public static ParcelFileDescriptor fromFd(FileDescriptor fd, Handler handler, final OnCloseListener listener) throws IOException { if (handler == null) { Loading @@ -318,7 +326,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { } if (status != null) { queue.removeOnFileDescriptorEventListener(fd); IoUtils.closeQuietly(fd); closeInternal(fd); listener.onClose(status.asIOException()); return 0; } Loading @@ -329,6 +337,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { return pfd; } @RavenwoodReplace private static FileDescriptor openInternal(File file, int mode) throws FileNotFoundException { if ((mode & MODE_WRITE_ONLY) != 0 && (mode & MODE_APPEND) == 0 && (mode & MODE_TRUNCATE) == 0 && ((mode & MODE_READ_ONLY) == 0) Loading @@ -352,17 +361,38 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { } } private static FileDescriptor openInternal$ravenwood(File file, int mode) throws FileNotFoundException { try { return native_open$ravenwood(file, mode); } catch (FileNotFoundException e) { throw e; } catch (IOException e) { throw new FileNotFoundException(e.getMessage()); } } @RavenwoodReplace private static void closeInternal(FileDescriptor fd) { IoUtils.closeQuietly(fd); } private static void closeInternal$ravenwood(FileDescriptor fd) { native_close$ravenwood(fd); } /** * Create a new ParcelFileDescriptor that is a dup of an existing * FileDescriptor. This obeys standard POSIX semantics, where the * new file descriptor shared state such as file position with the * original file descriptor. */ @RavenwoodThrow(reason = "Requires JNI support") public static ParcelFileDescriptor dup(FileDescriptor orig) throws IOException { try { final FileDescriptor fd = new FileDescriptor(); int intfd = Os.fcntlInt(orig, (isAtLeastQ() ? F_DUPFD_CLOEXEC : F_DUPFD), 0); fd.setInt$(intfd); setFdInt(fd, intfd); return new ParcelFileDescriptor(fd); } catch (ErrnoException e) { throw e.rethrowAsIOException(); Loading @@ -375,6 +405,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * new file descriptor shared state such as file position with the * original file descriptor. */ @RavenwoodThrow(reason = "Requires JNI support") public ParcelFileDescriptor dup() throws IOException { if (mWrapped != null) { return mWrapped.dup(); Loading @@ -393,14 +424,15 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * @return Returns a new ParcelFileDescriptor holding a FileDescriptor * for a dup of the given fd. */ @RavenwoodThrow(reason = "Requires JNI support") public static ParcelFileDescriptor fromFd(int fd) throws IOException { final FileDescriptor original = new FileDescriptor(); original.setInt$(fd); setFdInt(original, fd); try { final FileDescriptor dup = new FileDescriptor(); int intfd = Os.fcntlInt(original, (isAtLeastQ() ? F_DUPFD_CLOEXEC : F_DUPFD), 0); dup.setInt$(intfd); setFdInt(dup, intfd); return new ParcelFileDescriptor(dup); } catch (ErrnoException e) { throw e.rethrowAsIOException(); Loading @@ -423,7 +455,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { */ public static ParcelFileDescriptor adoptFd(int fd) { final FileDescriptor fdesc = new FileDescriptor(); fdesc.setInt$(fd); setFdInt(fdesc, fd); return new ParcelFileDescriptor(fdesc); } Loading Loading @@ -452,6 +484,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * * @throws UncheckedIOException if {@link #dup(FileDescriptor)} throws IOException. */ @RavenwoodThrow(reason = "Requires JNI support") public static ParcelFileDescriptor fromSocket(Socket socket) { FileDescriptor fd = socket.getFileDescriptor$(); try { Loading Loading @@ -485,6 +518,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * * @throws UncheckedIOException if {@link #dup(FileDescriptor)} throws IOException. */ @RavenwoodThrow(reason = "Requires JNI support") public static ParcelFileDescriptor fromDatagramSocket(DatagramSocket datagramSocket) { FileDescriptor fd = datagramSocket.getFileDescriptor$(); try { Loading @@ -499,6 +533,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * ParcelFileDescriptor in the returned array is the read side; the second * is the write side. */ @RavenwoodThrow(reason = "Requires JNI support") public static ParcelFileDescriptor[] createPipe() throws IOException { try { final FileDescriptor[] fds = Os.pipe2(ifAtLeastQ(O_CLOEXEC)); Loading @@ -520,6 +555,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * calling {@link #checkError()}, usually after detecting an EOF. * This can also be used to detect remote crashes. */ @RavenwoodThrow(reason = "Requires JNI support") public static ParcelFileDescriptor[] createReliablePipe() throws IOException { try { final FileDescriptor[] comm = createCommSocketPair(); Loading @@ -536,6 +572,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * Create two ParcelFileDescriptors structured as a pair of sockets * connected to each other. The two sockets are indistinguishable. */ @RavenwoodThrow(reason = "Requires JNI support") public static ParcelFileDescriptor[] createSocketPair() throws IOException { return createSocketPair(SOCK_STREAM); } Loading @@ -543,6 +580,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { /** * @hide */ @RavenwoodThrow(reason = "Requires JNI support") public static ParcelFileDescriptor[] createSocketPair(int type) throws IOException { try { final FileDescriptor fd0 = new FileDescriptor(); Loading @@ -565,6 +603,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * calling {@link #checkError()}, usually after detecting an EOF. * This can also be used to detect remote crashes. */ @RavenwoodThrow(reason = "Requires JNI support") public static ParcelFileDescriptor[] createReliableSocketPair() throws IOException { return createReliableSocketPair(SOCK_STREAM); } Loading @@ -572,6 +611,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { /** * @hide */ @RavenwoodThrow(reason = "Requires JNI support") public static ParcelFileDescriptor[] createReliableSocketPair(int type) throws IOException { try { final FileDescriptor[] comm = createCommSocketPair(); Loading @@ -586,6 +626,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { } } @RavenwoodThrow(reason = "Requires JNI support") private static FileDescriptor[] createCommSocketPair() throws IOException { try { // Use SOCK_SEQPACKET so that we have a guarantee that the status Loading Loading @@ -614,6 +655,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { */ @UnsupportedAppUsage @Deprecated @RavenwoodThrow(reason = "Requires JNI support") public static ParcelFileDescriptor fromData(byte[] data, String name) throws IOException { if (data == null) return null; MemoryFile file = new MemoryFile(name, data.length); Loading Loading @@ -669,9 +711,10 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * @hide */ @TestApi @RavenwoodThrow(reason = "Requires kernel support") public static File getFile(FileDescriptor fd) throws IOException { try { final String path = Os.readlink("/proc/self/fd/" + fd.getInt$()); final String path = Os.readlink("/proc/self/fd/" + getFdInt(fd)); if (OsConstants.S_ISREG(Os.stat(path).st_mode) || OsConstants.S_ISCHR(Os.stat(path).st_mode)) { return new File(path); Loading Loading @@ -700,6 +743,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * Return the total size of the file representing this fd, as determined by * {@code stat()}. Returns -1 if the fd is not a file. */ @RavenwoodThrow(reason = "Requires JNI support") public long getStatSize() { if (mWrapped != null) { return mWrapped.getStatSize(); Loading @@ -724,6 +768,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * @hide */ @UnsupportedAppUsage @RavenwoodThrow(reason = "Requires JNI support") public long seekTo(long pos) throws IOException { if (mWrapped != null) { return mWrapped.seekTo(pos); Loading Loading @@ -751,7 +796,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { if (mClosed) { throw new IllegalStateException("Already closed"); } return mFd.getInt$(); return getFdInt(mFd); } } Loading @@ -773,7 +818,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { if (mClosed) { throw new IllegalStateException("Already closed"); } int fd = IoUtils.acquireRawFd(mFd); int fd = acquireRawFd(mFd); writeCommStatusAndClose(Status.DETACHED, null); mClosed = true; mGuard.close(); Loading Loading @@ -832,7 +877,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { } // Status MUST be sent before closing actual descriptor writeCommStatusAndClose(status, msg); IoUtils.closeQuietly(mFd); closeInternal(mFd); releaseResources(); } Loading Loading @@ -899,7 +944,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { } } finally { IoUtils.closeQuietly(mCommFd); closeInternal(mCommFd); mCommFd = null; } } Loading Loading @@ -991,6 +1036,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * take care of calling {@link ParcelFileDescriptor#close * ParcelFileDescriptor.close()} for you when the stream is closed. */ @RavenwoodKeepWholeClass public static class AutoCloseInputStream extends FileInputStream { private final ParcelFileDescriptor mPfd; Loading Loading @@ -1042,6 +1088,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * take care of calling {@link ParcelFileDescriptor#close * ParcelFileDescriptor.close()} for you when the stream is closed. */ @RavenwoodKeepWholeClass public static class AutoCloseOutputStream extends FileOutputStream { private final ParcelFileDescriptor mPfd; Loading Loading @@ -1232,10 +1279,58 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { } } // These native methods are currently only implemented by Ravenwood, as it's the only // mechanism we have to jump to our RavenwoodNativeSubstitutionClass private static native void native_setFdInt$ravenwood(FileDescriptor fd, int fdInt); private static native int native_getFdInt$ravenwood(FileDescriptor fd); private static native FileDescriptor native_open$ravenwood(File file, int pfdMode) throws IOException; private static native void native_close$ravenwood(FileDescriptor fd); @RavenwoodReplace private static void setFdInt(FileDescriptor fd, int fdInt) { fd.setInt$(fdInt); } private static void setFdInt$ravenwood(FileDescriptor fd, int fdInt) { native_setFdInt$ravenwood(fd, fdInt); } @RavenwoodReplace private static int getFdInt(FileDescriptor fd) { return fd.getInt$(); } private static int getFdInt$ravenwood(FileDescriptor fd) { return native_getFdInt$ravenwood(fd); } @RavenwoodReplace private void setFdOwner(FileDescriptor fd) { IoUtils.setFdOwner(fd, this); } private void setFdOwner$ravenwood(FileDescriptor fd) { // FD owners currently unsupported under Ravenwood; ignored } @RavenwoodReplace private int acquireRawFd(FileDescriptor fd) { return IoUtils.acquireRawFd(fd); } private int acquireRawFd$ravenwood(FileDescriptor fd) { // FD owners currently unsupported under Ravenwood; return FD directly return getFdInt(fd); } @RavenwoodThrow private static boolean isAtLeastQ() { return (VMRuntime.getRuntime().getTargetSdkVersion() >= Build.VERSION_CODES.Q); } @RavenwoodThrow private static int ifAtLeastQ(int value) { return isAtLeastQ() ? value : 0; } Loading
core/java/android/util/CloseGuard.java +32 −4 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package android.util; import android.annotation.NonNull; import android.ravenwood.annotation.RavenwoodKeepWholeClass; import android.ravenwood.annotation.RavenwoodReplace; /** * CloseGuard is a mechanism for flagging implicit finalizer cleanup of Loading Loading @@ -108,15 +110,35 @@ import android.annotation.NonNull; * in a method, the call to {@code open} should occur just after * resource acquisition. */ @RavenwoodKeepWholeClass public final class CloseGuard { private final dalvik.system.CloseGuard mImpl; /** * Constructs a new CloseGuard instance. * {@link #open(String)} can be used to set up the instance to warn on failure to close. * * @hide */ public static CloseGuard get() { return new CloseGuard(); } /** * Constructs a new CloseGuard instance. * {@link #open(String)} can be used to set up the instance to warn on failure to close. */ public CloseGuard() { mImpl = dalvik.system.CloseGuard.get(); mImpl = getImpl(); } @RavenwoodReplace private dalvik.system.CloseGuard getImpl() { return dalvik.system.CloseGuard.get(); } private dalvik.system.CloseGuard getImpl$ravenwood() { return null; } /** Loading @@ -127,19 +149,25 @@ public final class CloseGuard { * @throws NullPointerException if closeMethodName is null. */ public void open(@NonNull String closeMethodName) { if (mImpl != null) { mImpl.open(closeMethodName); } } /** Marks this CloseGuard instance as closed to avoid warnings on finalization. */ public void close() { if (mImpl != null) { mImpl.close(); } } /** * Logs a warning if the caller did not properly cleanup by calling an explicit close method * before finalization. */ public void warnIfOpen() { if (mImpl != null) { mImpl.warnIfOpen(); } } }
ravenwood/ravenwood-annotation-allowed-classes.txt +4 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ com.android.internal.os.RuntimeInit com.android.internal.power.ModemPowerProfile android.util.AtomicFile android.util.CloseGuard android.util.DataUnit android.util.DayOfMonthCursor android.util.DumpableContainer Loading Loading @@ -68,6 +69,9 @@ android.os.Message android.os.MessageQueue android.os.PackageTagsList android.os.Parcel android.os.ParcelFileDescriptor android.os.ParcelFileDescriptor$AutoCloseInputStream android.os.ParcelFileDescriptor$AutoCloseOutputStream android.os.Parcelable android.os.PowerComponents android.os.Process Loading
tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/ParcelFileDescriptor_host.java 0 → 100644 +128 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.hoststubgen.nativesubstitution; import static android.os.ParcelFileDescriptor.MODE_APPEND; import static android.os.ParcelFileDescriptor.MODE_CREATE; import static android.os.ParcelFileDescriptor.MODE_READ_ONLY; import static android.os.ParcelFileDescriptor.MODE_READ_WRITE; import static android.os.ParcelFileDescriptor.MODE_TRUNCATE; import static android.os.ParcelFileDescriptor.MODE_WORLD_READABLE; import static android.os.ParcelFileDescriptor.MODE_WORLD_WRITEABLE; import static android.os.ParcelFileDescriptor.MODE_WRITE_ONLY; import com.android.internal.annotations.GuardedBy; import java.io.File; import java.io.FileDescriptor; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.RandomAccessFile; import java.util.HashMap; import java.util.Map; public class ParcelFileDescriptor_host { /** * Since we don't have a great way to keep an unmanaged {@code FileDescriptor} reference * alive, we keep a strong reference to the {@code RandomAccessFile} we used to open it. This * gives us a way to look up the original parent object when closing later. */ @GuardedBy("sActive") private static final Map<FileDescriptor, RandomAccessFile> sActive = new HashMap<>(); public static void native_setFdInt$ravenwood(FileDescriptor fd, int fdInt) { try { final Object obj = Class.forName("jdk.internal.access.SharedSecrets").getMethod( "getJavaIOFileDescriptorAccess").invoke(null); Class.forName("jdk.internal.access.JavaIOFileDescriptorAccess").getMethod( "set", FileDescriptor.class, int.class).invoke(obj, fd, fdInt); } catch (ReflectiveOperationException e) { throw new RuntimeException("Failed to interact with raw FileDescriptor internals;" + " perhaps JRE has changed?", e); } } public static int native_getFdInt$ravenwood(FileDescriptor fd) { try { final Object obj = Class.forName("jdk.internal.access.SharedSecrets").getMethod( "getJavaIOFileDescriptorAccess").invoke(null); return (int) Class.forName("jdk.internal.access.JavaIOFileDescriptorAccess").getMethod( "get", FileDescriptor.class).invoke(obj, fd); } catch (ReflectiveOperationException e) { throw new RuntimeException("Failed to interact with raw FileDescriptor internals;" + " perhaps JRE has changed?", e); } } public static FileDescriptor native_open$ravenwood(File file, int pfdMode) throws IOException { if ((pfdMode & MODE_CREATE) != 0 && !file.exists()) { throw new FileNotFoundException(); } final String modeString; if ((pfdMode & MODE_READ_WRITE) == MODE_READ_WRITE) { modeString = "rw"; } else if ((pfdMode & MODE_WRITE_ONLY) == MODE_WRITE_ONLY) { modeString = "rw"; } else if ((pfdMode & MODE_READ_ONLY) == MODE_READ_ONLY) { modeString = "r"; } else { throw new IllegalArgumentException(); } final RandomAccessFile raf = new RandomAccessFile(file, modeString); // Now that we have a real file on disk, match requested flags if ((pfdMode & MODE_TRUNCATE) != 0) { raf.setLength(0); } if ((pfdMode & MODE_APPEND) != 0) { raf.seek(raf.length()); } if ((pfdMode & MODE_WORLD_READABLE) != 0) { file.setReadable(true, false); } if ((pfdMode & MODE_WORLD_WRITEABLE) != 0) { file.setWritable(true, false); } final FileDescriptor fd = raf.getFD(); synchronized (sActive) { sActive.put(fd, raf); } return fd; } public static void native_close$ravenwood(FileDescriptor fd) { final RandomAccessFile raf; synchronized (sActive) { raf = sActive.remove(fd); } try { if (raf != null) { raf.close(); } else { // Odd, we don't remember opening this ourselves, but let's release the // underlying resource as requested System.err.println("Closing unknown FileDescriptor: " + fd); new FileOutputStream(fd).close(); } } catch (IOException ignored) { } } }