diff options
66 files changed, 4254 insertions, 637 deletions
diff --git a/Ravenwood.bp b/Ravenwood.bp index 412f2b746887..11da20aa6e02 100644 --- a/Ravenwood.bp +++ b/Ravenwood.bp @@ -284,6 +284,8 @@ android_ravenwood_libgroup { "100-framework-minus-apex.ravenwood", "200-kxml2-android", + "ravenwood-runtime-common-ravenwood", + "android.test.mock.ravenwood", "ravenwood-helper-runtime", "hoststubgen-helper-runtime.ravenwood", diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkRunner.java b/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkRunner.java index 515ddc8d1d49..a4128a3de52f 100644 --- a/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkRunner.java +++ b/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkRunner.java @@ -19,13 +19,16 @@ import android.annotation.Nullable; import android.os.Bundle; import android.os.SystemClock; import android.perftests.utils.ShellHelper; +import android.util.Log; import java.util.ArrayList; +import java.util.concurrent.TimeoutException; // Based on //platform/frameworks/base/apct-tests/perftests/utils/BenchmarkState.java public class BenchmarkRunner { - - private static final long COOL_OFF_PERIOD_MS = 1000; + private static final String TAG = BenchmarkRunner.class.getSimpleName(); + private static final int TIMEOUT_IN_SECONDS = 45; + private static final int CPU_IDLE_THRESHOLD_PERCENTAGE = 90; private static final int NUM_ITERATIONS = 4; @@ -79,8 +82,7 @@ public class BenchmarkRunner { } private void prepareForNextRun() { - SystemClock.sleep(COOL_OFF_PERIOD_MS); - ShellHelper.runShellCommand("am wait-for-broadcast-idle --flush-broadcast-loopers"); + waitCoolDownPeriod(); mStartTimeNs = System.nanoTime(); mPausedDurationNs = 0; } @@ -102,7 +104,7 @@ public class BenchmarkRunner { * to avoid unnecessary waiting. */ public void resumeTiming() { - ShellHelper.runShellCommand("am wait-for-broadcast-idle --flush-broadcast-loopers"); + waitCoolDownPeriod(); resumeTimer(); } @@ -162,4 +164,58 @@ public class BenchmarkRunner { } return null; } + + /** Waits for the CPU cores and the broadcast queue to be idle. */ + public void waitCoolDownPeriod() { + waitForCpuIdle(); + waitForBroadcastIdle(); + } + + private void waitForBroadcastIdle() { + try { + ShellHelper.runShellCommandWithTimeout( + "am wait-for-broadcast-idle --flush-broadcast-loopers", TIMEOUT_IN_SECONDS); + } catch (TimeoutException e) { + Log.e(TAG, "Ending waitForBroadcastIdle because it didn't finish in " + + TIMEOUT_IN_SECONDS + " seconds", e); + } + } + + private void waitForCpuIdle() { + int count = 0; + int idleCpuPercentage; + while (count++ < TIMEOUT_IN_SECONDS) { + idleCpuPercentage = getIdleCpuPercentage(); + Log.d(TAG, "Waiting for CPU idle #" + count + "=" + idleCpuPercentage + "%"); + if (idleCpuPercentage > CPU_IDLE_THRESHOLD_PERCENTAGE) { + return; + } + SystemClock.sleep(1000); + } + Log.e(TAG, "Ending waitForCpuIdle because it didn't finish in " + + TIMEOUT_IN_SECONDS + " seconds"); + } + + private int getIdleCpuPercentage() { + String output = ShellHelper.runShellCommand("top -m 1 -n 1"); + + String[] tokens = output.split("\\s+"); + + float totalCpu = -1; + float idleCpu = -1; + for (String token : tokens) { + if (token.contains("%cpu")) { + totalCpu = Float.parseFloat(token.split("%")[0]); + } else if (token.contains("%idle")) { + idleCpu = Float.parseFloat(token.split("%")[0]); + } + } + + if (totalCpu < 0 || idleCpu < 0) { + Log.e(TAG, "Could not get idle cpu percentage, output=" + output); + return -1; + } + + return (int) (100 * idleCpu / totalCpu); + } }
\ No newline at end of file diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java index 762e2af09cd3..98ab0c290e40 100644 --- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java +++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java @@ -188,21 +188,6 @@ public class UserLifecycleTests { } } - /** Tests creating a new user, with wait times between iterations. */ - @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS) - public void createUser_realistic() throws RemoteException { - while (mRunner.keepRunning()) { - Log.i(TAG, "Starting timer"); - final int userId = createUserNoFlags(); - - mRunner.pauseTiming(); - Log.i(TAG, "Stopping timer"); - removeUser(userId); - waitCoolDownPeriod(); - mRunner.resumeTimingForNextIteration(); - } - } - /** Tests creating and starting a new user. */ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS) public void createAndStartUser() throws RemoteException { @@ -239,7 +224,6 @@ public class UserLifecycleTests { mRunner.pauseTiming(); Log.d(TAG, "Stopping timer"); removeUser(userId); - waitCoolDownPeriod(); mRunner.resumeTimingForNextIteration(); } } @@ -254,7 +238,6 @@ public class UserLifecycleTests { mRunner.pauseTiming(); final int userId = createUserNoFlags(); - waitForBroadcastIdle(); runThenWaitForBroadcasts(userId, () -> { mRunner.resumeTiming(); Log.i(TAG, "Starting timer"); @@ -309,9 +292,6 @@ public class UserLifecycleTests { preStartUser(userId, numberOfIterationsToSkip); - waitForBroadcastIdle(); - waitCoolDownPeriod(); - runThenWaitForBroadcasts(userId, () -> { mRunner.resumeTiming(); Log.i(TAG, "Starting timer"); @@ -353,9 +333,6 @@ public class UserLifecycleTests { while (mRunner.keepRunning()) { mRunner.pauseTiming(); - waitForBroadcastIdle(); - waitCoolDownPeriod(); - runThenWaitForBroadcasts(userId, () -> { mRunner.resumeTiming(); Log.i(TAG, "Starting timer"); @@ -420,7 +397,6 @@ public class UserLifecycleTests { while (mRunner.keepRunning()) { mRunner.pauseTiming(); - waitCoolDownPeriod(); mRunner.resumeTiming(); Log.i(TAG, "Starting timer"); @@ -454,7 +430,6 @@ public class UserLifecycleTests { mRunner.pauseTiming(); Log.d(TAG, "Stopping timer"); removeUser(userId); - waitCoolDownPeriod(); mRunner.resumeTimingForNextIteration(); } } @@ -466,6 +441,7 @@ public class UserLifecycleTests { mRunner.pauseTiming(); final int startUser = mAm.getCurrentUser(); final int userId = createUserNoFlags(); + mRunner.resumeTiming(); Log.i(TAG, "Starting timer"); @@ -479,27 +455,6 @@ public class UserLifecycleTests { } } - /** Tests switching to an uninitialized user with wait times between iterations. */ - @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS) - public void switchUser_realistic() throws Exception { - while (mRunner.keepRunning()) { - mRunner.pauseTiming(); - final int startUser = ActivityManager.getCurrentUser(); - final int userId = createUserNoFlags(); - waitCoolDownPeriod(); - Log.d(TAG, "Starting timer"); - mRunner.resumeTiming(); - - switchUser(userId); - - mRunner.pauseTiming(); - Log.d(TAG, "Stopping timer"); - switchUserNoCheck(startUser); - removeUser(userId); - mRunner.resumeTimingForNextIteration(); - } - } - /** Tests switching to a previously-started, but no-longer-running, user. */ @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS) public void switchUser_stopped() throws RemoteException { @@ -507,6 +462,7 @@ public class UserLifecycleTests { mRunner.pauseTiming(); final int startUser = mAm.getCurrentUser(); final int testUser = initializeNewUserAndSwitchBack(/* stopNewUser */ true); + mRunner.resumeTiming(); Log.i(TAG, "Starting timer"); @@ -536,7 +492,6 @@ public class UserLifecycleTests { while (mRunner.keepRunning()) { mRunner.pauseTiming(); - waitCoolDownPeriod(); Log.d(TAG, "Starting timer"); mRunner.resumeTiming(); @@ -562,7 +517,6 @@ public class UserLifecycleTests { /* useStaticWallpaper */true); while (mRunner.keepRunning()) { mRunner.pauseTiming(); - waitCoolDownPeriod(); Log.d(TAG, "Starting timer"); mRunner.resumeTiming(); @@ -606,7 +560,6 @@ public class UserLifecycleTests { final int testUser = initializeNewUserAndSwitchBack(/* stopNewUser */ false); while (mRunner.keepRunning()) { mRunner.pauseTiming(); - waitCoolDownPeriod(); Log.d(TAG, "Starting timer"); mRunner.resumeTiming(); @@ -614,7 +567,6 @@ public class UserLifecycleTests { mRunner.pauseTiming(); Log.d(TAG, "Stopping timer"); - waitForBroadcastIdle(); switchUserNoCheck(startUser); mRunner.resumeTimingForNextIteration(); } @@ -631,7 +583,6 @@ public class UserLifecycleTests { /* useStaticWallpaper */ true); while (mRunner.keepRunning()) { mRunner.pauseTiming(); - waitCoolDownPeriod(); Log.d(TAG, "Starting timer"); mRunner.resumeTiming(); @@ -639,7 +590,6 @@ public class UserLifecycleTests { mRunner.pauseTiming(); Log.d(TAG, "Stopping timer"); - waitForBroadcastIdle(); switchUserNoCheck(startUser); mRunner.resumeTimingForNextIteration(); } @@ -675,13 +625,11 @@ public class UserLifecycleTests { @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS) public void stopUser_realistic() throws RemoteException { final int userId = createUserNoFlags(); - waitCoolDownPeriod(); while (mRunner.keepRunning()) { mRunner.pauseTiming(); runThenWaitForBroadcasts(userId, ()-> { mIam.startUserInBackground(userId); }, Intent.ACTION_USER_STARTED, Intent.ACTION_MEDIA_MOUNTED); - waitCoolDownPeriod(); Log.d(TAG, "Starting timer"); mRunner.resumeTiming(); @@ -703,7 +651,7 @@ public class UserLifecycleTests { final int startUser = mAm.getCurrentUser(); final int userId = createUserNoFlags(); - waitForBroadcastIdle(); + mRunner.waitCoolDownPeriod(); mUserSwitchWaiter.runThenWaitUntilBootCompleted(userId, () -> { mRunner.resumeTiming(); Log.i(TAG, "Starting timer"); @@ -726,7 +674,7 @@ public class UserLifecycleTests { final int startUser = ActivityManager.getCurrentUser(); final int userId = createUserNoFlags(); - waitCoolDownPeriod(); + mRunner.waitCoolDownPeriod(); mUserSwitchWaiter.runThenWaitUntilBootCompleted(userId, () -> { mRunner.resumeTiming(); Log.d(TAG, "Starting timer"); @@ -752,7 +700,7 @@ public class UserLifecycleTests { switchUser(userId); }, Intent.ACTION_MEDIA_MOUNTED); - waitForBroadcastIdle(); + mRunner.waitCoolDownPeriod(); mUserSwitchWaiter.runThenWaitUntilSwitchCompleted(startUser, () -> { runThenWaitForBroadcasts(userId, () -> { mRunner.resumeTiming(); @@ -781,7 +729,7 @@ public class UserLifecycleTests { switchUser(userId); }, Intent.ACTION_MEDIA_MOUNTED); - waitCoolDownPeriod(); + mRunner.waitCoolDownPeriod(); mUserSwitchWaiter.runThenWaitUntilSwitchCompleted(startUser, () -> { runThenWaitForBroadcasts(userId, () -> { mRunner.resumeTiming(); @@ -827,7 +775,6 @@ public class UserLifecycleTests { Log.d(TAG, "Stopping timer"); attestTrue("Failed creating profile " + userId, mUm.isManagedProfile(userId)); removeUser(userId); - waitCoolDownPeriod(); mRunner.resumeTimingForNextIteration(); } } @@ -868,7 +815,6 @@ public class UserLifecycleTests { mRunner.pauseTiming(); Log.d(TAG, "Stopping timer"); removeUser(userId); - waitCoolDownPeriod(); mRunner.resumeTimingForNextIteration(); } } @@ -913,7 +859,6 @@ public class UserLifecycleTests { mRunner.pauseTiming(); Log.d(TAG, "Stopping timer"); - waitCoolDownPeriod(); mRunner.resumeTimingForNextIteration(); } removeUser(userId); @@ -965,7 +910,6 @@ public class UserLifecycleTests { mRunner.pauseTiming(); Log.d(TAG, "Stopping timer"); removeUser(userId); - waitCoolDownPeriod(); mRunner.resumeTimingForNextIteration(); } } @@ -1030,7 +974,6 @@ public class UserLifecycleTests { mRunner.pauseTiming(); Log.d(TAG, "Stopping timer"); removeUser(userId); - waitCoolDownPeriod(); mRunner.resumeTimingForNextIteration(); } } @@ -1071,7 +1014,6 @@ public class UserLifecycleTests { mRunner.pauseTiming(); Log.d(TAG, "Stopping timer"); removeUser(userId); - waitCoolDownPeriod(); mRunner.resumeTimingForNextIteration(); } } @@ -1124,7 +1066,6 @@ public class UserLifecycleTests { mRunner.pauseTiming(); Log.d(TAG, "Stopping timer"); removeUser(userId); - waitCoolDownPeriod(); mRunner.resumeTimingForNextIteration(); } } @@ -1164,7 +1105,6 @@ public class UserLifecycleTests { runThenWaitForBroadcasts(userId, () -> { startUserInBackgroundAndWaitForUnlock(userId); }, Intent.ACTION_MEDIA_MOUNTED); - waitCoolDownPeriod(); mRunner.resumeTiming(); Log.d(TAG, "Starting timer"); @@ -1280,6 +1220,7 @@ public class UserLifecycleTests { * If lack of success should fail the test, use {@link #switchUser(int)} instead. */ private boolean switchUserNoCheck(int userId) throws RemoteException { + mRunner.waitCoolDownPeriod(); final boolean[] success = {true}; mUserSwitchWaiter.runThenWaitUntilSwitchCompleted(userId, () -> { mAm.switchUser(userId); @@ -1296,7 +1237,7 @@ public class UserLifecycleTests { */ private void stopUserAfterWaitingForBroadcastIdle(int userId) throws RemoteException { - waitForBroadcastIdle(); + mRunner.waitCoolDownPeriod(); stopUser(userId); } @@ -1438,6 +1379,8 @@ public class UserLifecycleTests { */ private void runThenWaitForBroadcasts(int userId, FunctionalUtils.ThrowingRunnable runnable, String... actions) { + mRunner.waitCoolDownPeriod(); + final String unreceivedAction = mBroadcastWaiter.runThenWaitForBroadcasts(userId, runnable, actions); @@ -1538,28 +1481,4 @@ public class UserLifecycleTests { assertEquals("", ShellHelper.runShellCommand("setprop " + name + " " + value)); return TextUtils.firstNotEmpty(oldValue, "invalid"); } - - private void waitForBroadcastIdle() { - try { - ShellHelper.runShellCommandWithTimeout( - "am wait-for-broadcast-idle --flush-broadcast-loopers", TIMEOUT_IN_SECOND); - } catch (TimeoutException e) { - Log.e(TAG, "Ending waitForBroadcastIdle because it is taking too long", e); - } - } - - private void sleep(long ms) { - try { - Thread.sleep(ms); - } catch (InterruptedException e) { - // Ignore - } - } - - private void waitCoolDownPeriod() { - // Heuristic value based on local tests. Stability increased compared to no waiting. - final int tenSeconds = 1000 * 10; - waitForBroadcastIdle(); - sleep(tenSeconds); - } } diff --git a/core/java/android/os/DeadObjectException.java b/core/java/android/os/DeadObjectException.java index fc3870e812a2..998e295da494 100644 --- a/core/java/android/os/DeadObjectException.java +++ b/core/java/android/os/DeadObjectException.java @@ -26,7 +26,7 @@ import android.os.RemoteException; * receive this error from an app, at a minimum, you should * recover by resetting the connection. For instance, you should * drop the binder, clean up associated state, and reset your - * connection to the service which through this error. In order + * connection to the service which threw this error. In order * to simplify your error recovery paths, you may also want to * "simply" restart your process. However, this may not be an * option if the service you are talking to is unreliable or @@ -34,9 +34,11 @@ import android.os.RemoteException; * * If this isn't from a service death and is instead from a * low-level binder error, it will be from: - * - a oneway call queue filling up (too many oneway calls) - * - from the binder buffer being filled up, so that the transaction - * is rejected. + * <ul> + * <li> a one-way call queue filling up (too many one-way calls) + * <li> from the binder buffer being filled up, so that the transaction + * is rejected. + * </ul> * * In these cases, more information about the error will be * logged. However, there isn't a good way to differentiate diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java index 17dfdda7dffc..71957ee3461e 100644 --- a/core/java/android/os/ParcelFileDescriptor.java +++ b/core/java/android/os/ParcelFileDescriptor.java @@ -52,6 +52,8 @@ import android.util.CloseGuard; import android.util.Log; import android.util.Slog; +import com.android.internal.ravenwood.RavenwoodEnvironment; + import dalvik.system.VMRuntime; import libcore.io.IoUtils; @@ -388,7 +390,6 @@ 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 static ParcelFileDescriptor dup(FileDescriptor orig) throws IOException { try { final FileDescriptor fd = new FileDescriptor(); @@ -406,7 +407,6 @@ 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(); @@ -425,7 +425,6 @@ 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(); setFdInt(original, fd); @@ -485,7 +484,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * * @throws UncheckedIOException if {@link #dup(FileDescriptor)} throws IOException. */ - @RavenwoodThrow(reason = "Requires JNI support") + @RavenwoodThrow(reason = "Socket.getFileDescriptor$()") public static ParcelFileDescriptor fromSocket(Socket socket) { FileDescriptor fd = socket.getFileDescriptor$(); try { @@ -519,7 +518,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * * @throws UncheckedIOException if {@link #dup(FileDescriptor)} throws IOException. */ - @RavenwoodThrow(reason = "Requires JNI support") + @RavenwoodThrow(reason = "DatagramSocket.getFileDescriptor$()") public static ParcelFileDescriptor fromDatagramSocket(DatagramSocket datagramSocket) { FileDescriptor fd = datagramSocket.getFileDescriptor$(); try { @@ -534,7 +533,6 @@ 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)); @@ -556,7 +554,6 @@ 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(); @@ -573,7 +570,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") + @RavenwoodThrow(reason = "Os.socketpair()") public static ParcelFileDescriptor[] createSocketPair() throws IOException { return createSocketPair(SOCK_STREAM); } @@ -581,7 +578,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { /** * @hide */ - @RavenwoodThrow(reason = "Requires JNI support") + @RavenwoodThrow(reason = "Os.socketpair()") public static ParcelFileDescriptor[] createSocketPair(int type) throws IOException { try { final FileDescriptor fd0 = new FileDescriptor(); @@ -604,7 +601,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") + @RavenwoodThrow(reason = "Os.socketpair()") public static ParcelFileDescriptor[] createReliableSocketPair() throws IOException { return createReliableSocketPair(SOCK_STREAM); } @@ -612,7 +609,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { /** * @hide */ - @RavenwoodThrow(reason = "Requires JNI support") + @RavenwoodThrow(reason = "Os.socketpair()") public static ParcelFileDescriptor[] createReliableSocketPair(int type) throws IOException { try { final FileDescriptor[] comm = createCommSocketPair(); @@ -627,7 +624,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { } } - @RavenwoodThrow(reason = "Requires JNI support") + @RavenwoodThrow(reason = "Os.socketpair()") private static FileDescriptor[] createCommSocketPair() throws IOException { try { // Use SOCK_SEQPACKET so that we have a guarantee that the status @@ -656,7 +653,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { */ @UnsupportedAppUsage @Deprecated - @RavenwoodThrow(reason = "Requires JNI support") + @RavenwoodThrow(blockedBy = MemoryFile.class) public static ParcelFileDescriptor fromData(byte[] data, String name) throws IOException { if (data == null) return null; MemoryFile file = new MemoryFile(name, data.length); @@ -712,7 +709,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { * @hide */ @TestApi - @RavenwoodThrow(reason = "Requires kernel support") + @RavenwoodThrow(reason = "Os.readlink() and Os.stat()") public static File getFile(FileDescriptor fd) throws IOException { try { final String path = Os.readlink("/proc/self/fd/" + getFdInt(fd)); @@ -744,7 +741,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") + @RavenwoodThrow(reason = "Os.readlink() and Os.stat()") public long getStatSize() { if (mWrapped != null) { return mWrapped.getStatSize(); @@ -769,7 +766,6 @@ 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); @@ -1037,7 +1033,6 @@ 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; @@ -1326,12 +1321,15 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { } - @RavenwoodThrow + @RavenwoodReplace private static boolean isAtLeastQ() { return (VMRuntime.getRuntime().getTargetSdkVersion() >= Build.VERSION_CODES.Q); } - @RavenwoodThrow + private static boolean isAtLeastQ$ravenwood() { + return RavenwoodEnvironment.workaround().isTargetSdkAtLeastQ(); + } + private static int ifAtLeastQ(int value) { return isAtLeastQ() ? value : 0; } diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index 1fc98cfa7eb4..a9846fb5751f 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -1262,15 +1262,11 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation mHost.getInputMethodManager(), null /* icProto */); } - final var statsToken = (types & ime()) == 0 ? null - : ImeTracker.forLogging().onStart(ImeTracker.TYPE_USER, - ImeTracker.ORIGIN_CLIENT, - SoftInputShowHideReason.CONTROL_WINDOW_INSETS_ANIMATION, - mHost.isHandlingPointerEvent() /* fromUser */); + // TODO(b/342111149): Create statsToken here once ImeTracker#onStart becomes async. controlAnimationUnchecked(types, cancellationSignal, listener, mFrame, fromIme, durationMs, interpolator, animationType, getLayoutInsetsDuringAnimationMode(types, fromPredictiveBack), - false /* useInsetsAnimationThread */, statsToken); + false /* useInsetsAnimationThread */, null); } private void controlAnimationUnchecked(@InsetsType int types, diff --git a/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java b/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java index 149442556676..8fe1813b7ba0 100644 --- a/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java +++ b/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java @@ -27,6 +27,7 @@ public final class RavenwoodEnvironment { public static final String TAG = "RavenwoodEnvironment"; private static RavenwoodEnvironment sInstance = new RavenwoodEnvironment(); + private static Workaround sWorkaround = new Workaround(); private RavenwoodEnvironment() { if (isRunningOnRavenwood()) { @@ -76,4 +77,30 @@ public final class RavenwoodEnvironment { private boolean isRunningOnRavenwood$ravenwood() { return true; } + + /** + * See {@link Workaround}. It's only usablke on Ravenwood. + */ + public static Workaround workaround() { + if (getInstance().isRunningOnRavenwood()) { + return sWorkaround; + } + throw new IllegalStateException("Workaround can only be used on Ravenwood"); + } + + /** + * A set of APIs used to work around missing features on Ravenwood. Ideally, this class should + * be empty, and all its APIs should be able to be implemented properly. + */ + public static class Workaround { + Workaround() { + } + + /** + * @return whether the app's target SDK level is at least Q. + */ + public boolean isTargetSdkAtLeastQ() { + return true; + } + } } diff --git a/libs/WindowManager/Shell/res/drawable/circular_progress.xml b/libs/WindowManager/Shell/res/drawable/circular_progress.xml index 294b1f0e21fd..0d64527b6c13 100644 --- a/libs/WindowManager/Shell/res/drawable/circular_progress.xml +++ b/libs/WindowManager/Shell/res/drawable/circular_progress.xml @@ -24,7 +24,7 @@ android:toDegrees="275"> <shape android:shape="ring" - android:thickness="3dp" + android:thickness="2dp" android:innerRadius="14dp" android:useLevel="true"> </shape> diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml index 4d06dd3b9318..84e144972f38 100644 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml @@ -28,13 +28,11 @@ <LinearLayout android:id="@+id/open_menu_button" android:layout_width="wrap_content" - android:layout_height="match_parent" - android:tint="?androidprv:attr/materialColorOnSurface" - android:background="?android:selectableItemBackground" + android:layout_height="40dp" android:orientation="horizontal" android:clickable="true" android:focusable="true" - android:paddingStart="12dp"> + android:layout_marginStart="12dp"> <ImageView android:id="@+id/application_icon" android:layout_width="@dimen/desktop_mode_caption_icon_radius" @@ -85,8 +83,6 @@ android:layout_height="40dp" android:layout_gravity="end" android:layout_marginHorizontal="8dp" - android:paddingHorizontal="5dp" - android:paddingVertical="3dp" android:clickable="true" android:focusable="true"/> @@ -97,7 +93,6 @@ android:paddingHorizontal="10dp" android:paddingVertical="8dp" android:layout_marginEnd="8dp" - android:background="?android:selectableItemBackgroundBorderless" android:contentDescription="@string/close_button_text" android:src="@drawable/desktop_mode_header_ic_close" android:scaleType="centerCrop" diff --git a/libs/WindowManager/Shell/res/layout/maximize_menu_button.xml b/libs/WindowManager/Shell/res/layout/maximize_menu_button.xml index 77507a468f94..cf1b8947467e 100644 --- a/libs/WindowManager/Shell/res/layout/maximize_menu_button.xml +++ b/libs/WindowManager/Shell/res/layout/maximize_menu_button.xml @@ -16,20 +16,28 @@ <merge xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> - <ProgressBar - android:id="@+id/progress_bar" - style="?android:attr/progressBarStyleHorizontal" - android:progressDrawable="@drawable/circular_progress" - android:layout_width="34dp" - android:layout_height="34dp" - android:indeterminate="false" - android:visibility="invisible"/> + + <FrameLayout + android:layout_width="44dp" + android:layout_height="40dp"> + <ProgressBar + android:id="@+id/progress_bar" + style="?android:attr/progressBarStyleHorizontal" + android:progressDrawable="@drawable/circular_progress" + android:layout_width="32dp" + android:layout_height="32dp" + android:indeterminate="false" + android:layout_marginHorizontal="6dp" + android:layout_marginVertical="4dp" + android:visibility="invisible"/> + </FrameLayout> <ImageButton android:id="@+id/maximize_window" - android:layout_width="34dp" - android:layout_height="34dp" - android:padding="5dp" + android:layout_width="44dp" + android:layout_height="40dp" + android:paddingHorizontal="10dp" + android:paddingVertical="8dp" android:contentDescription="@string/maximize_button_text" android:src="@drawable/decor_desktop_mode_maximize_button_dark" android:scaleType="fitCenter" /> diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index 8bc3004a2ba6..f27f46c07de6 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -553,6 +553,25 @@ <!-- The corner radius of a task that was dragged from fullscreen. --> <dimen name="desktop_mode_dragged_task_radius">28dp</dimen> + <!-- The corner radius of the app chip, maximize and close button's ripple drawable --> + <dimen name="desktop_mode_header_buttons_ripple_radius">16dp</dimen> + <!-- The vertical inset to apply to the app chip's ripple drawable --> + <dimen name="desktop_mode_header_app_chip_ripple_inset_vertical">4dp</dimen> + + <!-- The corner radius of the maximize button's ripple drawable --> + <dimen name="desktop_mode_header_maximize_ripple_radius">18dp</dimen> + <!-- The vertical inset to apply to the maximize button's ripple drawable --> + <dimen name="desktop_mode_header_maximize_ripple_inset_vertical">4dp</dimen> + <!-- The horizontal inset to apply to the maximize button's ripple drawable --> + <dimen name="desktop_mode_header_maximize_ripple_inset_horizontal">6dp</dimen> + + <!-- The corner radius of the close button's ripple drawable --> + <dimen name="desktop_mode_header_close_ripple_radius">18dp</dimen> + <!-- The vertical inset to apply to the close button's ripple drawable --> + <dimen name="desktop_mode_header_close_ripple_inset_vertical">4dp</dimen> + <!-- The horizontal inset to apply to the close button's ripple drawable --> + <dimen name="desktop_mode_header_close_ripple_inset_horizontal">6dp</dimen> + <!-- The acceptable area ratio of fg icon area/bg icon area, i.e. (72 x 72) / (108 x 108) --> <item type="dimen" format="float" name="splash_icon_enlarge_foreground_threshold">0.44</item> <!-- Scaling factor applied to splash icons without provided background i.e. (192 / 160) --> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt index 53bdda192757..78f0ef7af45c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt @@ -28,7 +28,6 @@ import android.view.View import android.widget.FrameLayout import android.widget.ImageButton import android.widget.ProgressBar -import androidx.annotation.ColorInt import androidx.core.animation.doOnEnd import androidx.core.animation.doOnStart import androidx.core.content.ContextCompat @@ -106,30 +105,17 @@ class MaximizeButtonView( fun setAnimationTints( darkMode: Boolean, iconForegroundColor: ColorStateList? = null, - baseForegroundColor: Int? = null + baseForegroundColor: Int? = null, + rippleDrawable: RippleDrawable? = null ) { if (Flags.enableThemedAppHeaders()) { requireNotNull(iconForegroundColor) { "Icon foreground color must be non-null" } requireNotNull(baseForegroundColor) { "Base foreground color must be non-null" } + requireNotNull(rippleDrawable) { "Ripple drawable must be non-null" } maximizeWindow.imageTintList = iconForegroundColor - maximizeWindow.background = RippleDrawable( - ColorStateList( - arrayOf( - intArrayOf(android.R.attr.state_hovered), - intArrayOf(android.R.attr.state_pressed), - intArrayOf(), - ), - intArrayOf( - replaceColorAlpha(baseForegroundColor, OPACITY_8), - replaceColorAlpha(baseForegroundColor, OPACITY_12), - Color.TRANSPARENT - ) - ), - null, - null - ) + maximizeWindow.background = rippleDrawable progressBar.progressTintList = ColorStateList.valueOf(baseForegroundColor) - .withAlpha(OPACITY_12) + .withAlpha(OPACITY_15) progressBar.progressBackgroundTintList = ColorStateList.valueOf(Color.TRANSPARENT) } else { if (darkMode) { @@ -146,18 +132,7 @@ class MaximizeButtonView( } } - @ColorInt - private fun replaceColorAlpha(@ColorInt color: Int, alpha: Int): Int { - return Color.argb( - alpha, - Color.red(color), - Color.green(color), - Color.blue(color) - ) - } - companion object { - private const val OPACITY_8 = 20 - private const val OPACITY_12 = 31 + private const val OPACITY_15 = 38 } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt index 1c4b742b6fb2..3c12da2d6620 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt @@ -9,6 +9,9 @@ import android.graphics.Bitmap import android.graphics.Color import android.graphics.drawable.GradientDrawable import android.graphics.drawable.LayerDrawable +import android.graphics.drawable.RippleDrawable +import android.graphics.drawable.ShapeDrawable +import android.graphics.drawable.shapes.RoundRectShape import android.view.View import android.view.View.OnLongClickListener import android.widget.ImageButton @@ -46,6 +49,38 @@ internal class DesktopModeAppControlsWindowDecorationViewHolder( onMaximizeHoverAnimationFinishedListener: () -> Unit ) : DesktopModeWindowDecorationViewHolder(rootView) { + /** + * The corner radius to apply to the app chip, maximize and close button's background drawable. + **/ + private val headerButtonsRippleRadius = context.resources + .getDimensionPixelSize(R.dimen.desktop_mode_header_buttons_ripple_radius) + + /** + * The app chip, maximize and close button's height extends to the top & bottom edges of the + * header, and their width may be larger than their height. This is by design to increase the + * clickable and hover-able bounds of the view as much as possible. However, to prevent the + * ripple drawable from being as large as the views (and asymmetrical), insets are applied to + * the background ripple drawable itself to give the appearance of a smaller button + * (with padding between itself and the header edges / sibling buttons) but without affecting + * its touchable region. + */ + private val appChipDrawableInsets = DrawableInsets( + vertical = context.resources + .getDimensionPixelSize(R.dimen.desktop_mode_header_app_chip_ripple_inset_vertical) + ) + private val maximizeDrawableInsets = DrawableInsets( + vertical = context.resources + .getDimensionPixelSize(R.dimen.desktop_mode_header_maximize_ripple_inset_vertical), + horizontal = context.resources + .getDimensionPixelSize(R.dimen.desktop_mode_header_maximize_ripple_inset_horizontal) + ) + private val closeDrawableInsets = DrawableInsets( + vertical = context.resources + .getDimensionPixelSize(R.dimen.desktop_mode_header_close_ripple_inset_vertical), + horizontal = context.resources + .getDimensionPixelSize(R.dimen.desktop_mode_header_close_ripple_inset_horizontal) + ) + private val captionView: View = rootView.requireViewById(R.id.desktop_mode_caption) private val captionHandle: View = rootView.requireViewById(R.id.caption_handle) private val openMenuButton: View = rootView.requireViewById(R.id.open_menu_button) @@ -97,7 +132,19 @@ internal class DesktopModeAppControlsWindowDecorationViewHolder( maximizeWindowButton.imageAlpha = alpha closeWindowButton.imageAlpha = alpha expandMenuButton.imageAlpha = alpha - + context.withStyledAttributes( + set = null, + attrs = intArrayOf( + android.R.attr.selectableItemBackground, + android.R.attr.selectableItemBackgroundBorderless + ), + defStyleAttr = 0, + defStyleRes = 0 + ) { + openMenuButton.background = getDrawable(0) + maximizeWindowButton.background = getDrawable(1) + closeWindowButton.background = getDrawable(1) + } maximizeButtonView.setAnimationTints(isDarkMode()) } @@ -126,18 +173,40 @@ internal class DesktopModeAppControlsWindowDecorationViewHolder( val foregroundColor = headerStyle.foreground.color val foregroundAlpha = headerStyle.foreground.opacity val colorStateList = ColorStateList.valueOf(foregroundColor).withAlpha(foregroundAlpha) - closeWindowButton.imageTintList = colorStateList - expandMenuButton.imageTintList = colorStateList - with (appNameTextView) { - isVisible = header.type == Header.Type.DEFAULT - setTextColor(colorStateList) + // App chip. + openMenuButton.apply { + background = createRippleDrawable( + color = foregroundColor, + cornerRadius = headerButtonsRippleRadius, + drawableInsets = appChipDrawableInsets, + ) + expandMenuButton.imageTintList = colorStateList + appNameTextView.apply { + isVisible = header.type == Header.Type.DEFAULT + setTextColor(colorStateList) + } + appIconImageView.imageAlpha = foregroundAlpha } - appIconImageView.imageAlpha = foregroundAlpha + // Maximize button. maximizeButtonView.setAnimationTints( darkMode = header.appTheme == Header.Theme.DARK, iconForegroundColor = colorStateList, - baseForegroundColor = foregroundColor + baseForegroundColor = foregroundColor, + rippleDrawable = createRippleDrawable( + color = foregroundColor, + cornerRadius = headerButtonsRippleRadius, + drawableInsets = maximizeDrawableInsets + ) ) + // Close button. + closeWindowButton.apply { + imageTintList = colorStateList + background = createRippleDrawable( + color = foregroundColor, + cornerRadius = headerButtonsRippleRadius, + drawableInsets = closeDrawableInsets + ) + } } override fun onHandleMenuOpened() {} @@ -390,10 +459,61 @@ internal class DesktopModeAppControlsWindowDecorationViewHolder( context.withStyledAttributes(null, intArrayOf(attr), 0, 0) { return getColor(0, 0) } - return Color.BLACK + return Color.WHITE + } + + @ColorInt + private fun replaceColorAlpha(@ColorInt color: Int, alpha: Int): Int { + return Color.argb( + alpha, + Color.red(color), + Color.green(color), + Color.blue(color) + ) + } + + private fun createRippleDrawable( + @ColorInt color: Int, + cornerRadius: Int, + drawableInsets: DrawableInsets, + ): RippleDrawable { + return RippleDrawable( + ColorStateList( + arrayOf( + intArrayOf(android.R.attr.state_hovered), + intArrayOf(android.R.attr.state_pressed), + intArrayOf(), + ), + intArrayOf( + replaceColorAlpha(color, OPACITY_11), + replaceColorAlpha(color, OPACITY_15), + Color.TRANSPARENT + ) + ), + null /* content */, + LayerDrawable(arrayOf( + ShapeDrawable().apply { + shape = RoundRectShape( + FloatArray(8) { cornerRadius.toFloat() }, + null /* inset */, + null /* innerRadii */ + ) + paint.color = Color.WHITE + } + )).apply { + require(numberOfLayers == 1) { "Must only contain one layer" } + setLayerInset(0 /* index */, + drawableInsets.l, drawableInsets.t, drawableInsets.r, drawableInsets.b) + } + ) + } + + private data class DrawableInsets(val l: Int, val t: Int, val r: Int, val b: Int) { + constructor(vertical: Int = 0, horizontal: Int = 0) : + this(horizontal, vertical, horizontal, vertical) } - data class Header( + private data class Header( val type: Type, val systemTheme: Theme, val appTheme: Theme, @@ -408,7 +528,7 @@ internal class DesktopModeAppControlsWindowDecorationViewHolder( private fun Header.Theme.isDark(): Boolean = this == Header.Theme.DARK - data class HeaderStyle( + private data class HeaderStyle( val background: Background, val foreground: Foreground ) { @@ -497,6 +617,8 @@ internal class DesktopModeAppControlsWindowDecorationViewHolder( private const val FOCUSED_OPACITY = 255 private const val OPACITY_100 = 255 + private const val OPACITY_11 = 28 + private const val OPACITY_15 = 38 private const val OPACITY_30 = 77 private const val OPACITY_55 = 140 private const val OPACITY_65 = 166 diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java index 838630fcccb9..0589c0f12ab6 100644 --- a/media/java/android/media/MediaRoute2Info.java +++ b/media/java/android/media/MediaRoute2Info.java @@ -523,7 +523,7 @@ public final class MediaRoute2Info implements Parcelable { private final int mConnectionState; private final String mClientPackageName; private final String mPackageName; - private final int mVolumeHandling; + @PlaybackVolume private final int mVolumeHandling; private final int mVolumeMax; private final int mVolume; private final String mAddress; @@ -855,25 +855,7 @@ public final class MediaRoute2Info implements Parcelable { } private void dumpVolume(@NonNull PrintWriter pw, @NonNull String prefix) { - String volumeHandlingName; - - switch (mVolumeHandling) { - case PLAYBACK_VOLUME_FIXED: - volumeHandlingName = "FIXED"; - break; - case PLAYBACK_VOLUME_VARIABLE: - volumeHandlingName = "VARIABLE"; - break; - default: - volumeHandlingName = "UNKNOWN"; - break; - } - - String volume = String.format(Locale.US, - "volume(current=%d, max=%d, handling=%s(%d))", - mVolume, mVolumeMax, volumeHandlingName, mVolumeHandling); - - pw.println(prefix + volume); + pw.println(prefix + getVolumeString(mVolume, mVolumeMax, mVolumeHandling)); } @Override @@ -936,47 +918,42 @@ public final class MediaRoute2Info implements Parcelable { @Override public String toString() { // Note: mExtras is not printed here. - StringBuilder result = - new StringBuilder() - .append("MediaRoute2Info{ ") - .append("id=") - .append(getId()) - .append(", name=") - .append(getName()) - .append(", type=") - .append(getDeviceTypeString(getType())) - .append(", isSystem=") - .append(isSystemRoute()) - .append(", features=") - .append(getFeatures()) - .append(", iconUri=") - .append(getIconUri()) - .append(", description=") - .append(getDescription()) - .append(", connectionState=") - .append(getConnectionState()) - .append(", clientPackageName=") - .append(getClientPackageName()) - .append(", volumeHandling=") - .append(getVolumeHandling()) - .append(", volumeMax=") - .append(getVolumeMax()) - .append(", volume=") - .append(getVolume()) - .append(", address=") - .append(getAddress()) - .append(", deduplicationIds=") - .append(String.join(",", getDeduplicationIds())) - .append(", providerId=") - .append(getProviderId()) - .append(", isVisibilityRestricted=") - .append(mIsVisibilityRestricted) - .append(", allowedPackages=") - .append(String.join(",", mAllowedPackages)) - .append(", suitabilityStatus=") - .append(mSuitabilityStatus) - .append(" }"); - return result.toString(); + return new StringBuilder() + .append("MediaRoute2Info{ ") + .append("id=") + .append(getId()) + .append(", name=") + .append(getName()) + .append(", type=") + .append(getDeviceTypeString(getType())) + .append(", isSystem=") + .append(isSystemRoute()) + .append(", features=") + .append(getFeatures()) + .append(", iconUri=") + .append(getIconUri()) + .append(", description=") + .append(getDescription()) + .append(", connectionState=") + .append(getConnectionState()) + .append(", clientPackageName=") + .append(getClientPackageName()) + .append(", ") + .append(getVolumeString(mVolume, mVolumeMax, mVolumeHandling)) + .append(", address=") + .append(getAddress()) + .append(", deduplicationIds=") + .append(String.join(",", getDeduplicationIds())) + .append(", providerId=") + .append(getProviderId()) + .append(", isVisibilityRestricted=") + .append(mIsVisibilityRestricted) + .append(", allowedPackages=") + .append(String.join(",", mAllowedPackages)) + .append(", suitabilityStatus=") + .append(mSuitabilityStatus) + .append(" }") + .toString(); } @Override @@ -1008,6 +985,36 @@ public final class MediaRoute2Info implements Parcelable { dest.writeInt(mSuitabilityStatus); } + /** + * Returns a human readable string describing the given volume values. + * + * @param volume The current volume. + * @param maxVolume The maximum volume. + * @param volumeHandling The {@link PlaybackVolume}. + */ + /* package */ static String getVolumeString( + int volume, int maxVolume, @PlaybackVolume int volumeHandling) { + String volumeHandlingName; + switch (volumeHandling) { + case PLAYBACK_VOLUME_FIXED: + volumeHandlingName = "FIXED"; + break; + case PLAYBACK_VOLUME_VARIABLE: + volumeHandlingName = "VARIABLE"; + break; + default: + volumeHandlingName = "UNKNOWN"; + break; + } + return String.format( + Locale.US, + "volume(current=%d, max=%d, handling=%s(%d))", + volume, + maxVolume, + volumeHandlingName, + volumeHandling); + } + private static String getDeviceTypeString(@Type int deviceType) { switch (deviceType) { case TYPE_BUILTIN_SPEAKER: @@ -1079,7 +1086,7 @@ public final class MediaRoute2Info implements Parcelable { private int mConnectionState; private String mClientPackageName; private String mPackageName; - private int mVolumeHandling = PLAYBACK_VOLUME_FIXED; + @PlaybackVolume private int mVolumeHandling = PLAYBACK_VOLUME_FIXED; private int mVolumeMax; private int mVolume; private String mAddress; diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java index e62d112a7ccb..8fa0e49e8b96 100644 --- a/media/java/android/media/MediaRouter2Manager.java +++ b/media/java/android/media/MediaRouter2Manager.java @@ -402,9 +402,6 @@ public final class MediaRouter2Manager { @Nullable public RoutingSessionInfo getRoutingSessionForMediaController(MediaController mediaController) { MediaController.PlaybackInfo playbackInfo = mediaController.getPlaybackInfo(); - if (playbackInfo == null) { - return null; - } if (playbackInfo.getPlaybackType() == MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL) { return getSystemRoutingSession(mediaController.getPackageName()); } @@ -959,10 +956,6 @@ public final class MediaRouter2Manager { private boolean areSessionsMatched(MediaController mediaController, RoutingSessionInfo sessionInfo) { MediaController.PlaybackInfo playbackInfo = mediaController.getPlaybackInfo(); - if (playbackInfo == null) { - return false; - } - String volumeControlId = playbackInfo.getVolumeControlId(); if (volumeControlId == null) { return false; diff --git a/media/java/android/media/RoutingSessionInfo.java b/media/java/android/media/RoutingSessionInfo.java index a3c8b689f0a6..a2a16ef5230b 100644 --- a/media/java/android/media/RoutingSessionInfo.java +++ b/media/java/android/media/RoutingSessionInfo.java @@ -107,7 +107,7 @@ public final class RoutingSessionInfo implements Parcelable { @NonNull final List<String> mTransferableRoutes; - final int mVolumeHandling; + @MediaRoute2Info.PlaybackVolume final int mVolumeHandling; final int mVolumeMax; final int mVolume; @@ -207,9 +207,10 @@ public final class RoutingSessionInfo implements Parcelable { return controlHints; } + @MediaRoute2Info.PlaybackVolume private static int defineVolumeHandling( boolean isSystemSession, - int volumeHandling, + @MediaRoute2Info.PlaybackVolume int volumeHandling, List<String> selectedRoutes, boolean volumeAdjustmentForRemoteGroupSessions) { if (!isSystemSession @@ -439,9 +440,7 @@ public final class RoutingSessionInfo implements Parcelable { pw.println(indent + "mSelectableRoutes=" + mSelectableRoutes); pw.println(indent + "mDeselectableRoutes=" + mDeselectableRoutes); pw.println(indent + "mTransferableRoutes=" + mTransferableRoutes); - pw.println(indent + "mVolumeHandling=" + mVolumeHandling); - pw.println(indent + "mVolumeMax=" + mVolumeMax); - pw.println(indent + "mVolume=" + mVolume); + pw.println(indent + MediaRoute2Info.getVolumeString(mVolume, mVolumeMax, mVolumeHandling)); pw.println(indent + "mControlHints=" + mControlHints); pw.println(indent + "mIsSystemSession=" + mIsSystemSession); pw.println(indent + "mTransferReason=" + mTransferReason); @@ -503,41 +502,36 @@ public final class RoutingSessionInfo implements Parcelable { @Override public String toString() { - StringBuilder result = - new StringBuilder() - .append("RoutingSessionInfo{ ") - .append("sessionId=") - .append(getId()) - .append(", name=") - .append(getName()) - .append(", clientPackageName=") - .append(getClientPackageName()) - .append(", selectedRoutes={") - .append(String.join(",", getSelectedRoutes())) - .append("}") - .append(", selectableRoutes={") - .append(String.join(",", getSelectableRoutes())) - .append("}") - .append(", deselectableRoutes={") - .append(String.join(",", getDeselectableRoutes())) - .append("}") - .append(", transferableRoutes={") - .append(String.join(",", getTransferableRoutes())) - .append("}") - .append(", volumeHandling=") - .append(getVolumeHandling()) - .append(", volumeMax=") - .append(getVolumeMax()) - .append(", volume=") - .append(getVolume()) - .append(", transferReason=") - .append(getTransferReason()) - .append(", transferInitiatorUserHandle=") - .append(getTransferInitiatorUserHandle()) - .append(", transferInitiatorPackageName=") - .append(getTransferInitiatorPackageName()) - .append(" }"); - return result.toString(); + return new StringBuilder() + .append("RoutingSessionInfo{ ") + .append("sessionId=") + .append(getId()) + .append(", name=") + .append(getName()) + .append(", clientPackageName=") + .append(getClientPackageName()) + .append(", selectedRoutes={") + .append(String.join(",", getSelectedRoutes())) + .append("}") + .append(", selectableRoutes={") + .append(String.join(",", getSelectableRoutes())) + .append("}") + .append(", deselectableRoutes={") + .append(String.join(",", getDeselectableRoutes())) + .append("}") + .append(", transferableRoutes={") + .append(String.join(",", getTransferableRoutes())) + .append("}") + .append(", ") + .append(MediaRoute2Info.getVolumeString(mVolume, mVolumeMax, mVolumeHandling)) + .append(", transferReason=") + .append(getTransferReason()) + .append(", transferInitiatorUserHandle=") + .append(getTransferInitiatorUserHandle()) + .append(", transferInitiatorPackageName=") + .append(getTransferInitiatorPackageName()) + .append(" }") + .toString(); } /** @@ -586,6 +580,7 @@ public final class RoutingSessionInfo implements Parcelable { private final List<String> mDeselectableRoutes; @NonNull private final List<String> mTransferableRoutes; + @MediaRoute2Info.PlaybackVolume private int mVolumeHandling = MediaRoute2Info.PLAYBACK_VOLUME_FIXED; private int mVolumeMax; private int mVolume; diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index ac680a97cf3a..e940674a1cf5 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -752,6 +752,7 @@ android_robolectric_test { plugins: [ "dagger2-compiler", ], + strict_mode: false, } // in-place tests which use Robolectric in the tests directory @@ -771,7 +772,6 @@ android_robolectric_test { ], static_libs: [ "RoboTestLibraries", - "mockito-kotlin2", ], libs: [ "android.test.runner", @@ -787,6 +787,7 @@ android_robolectric_test { plugins: [ "dagger2-compiler", ], + strict_mode: false, } android_ravenwood_test { diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt index 99f7d0f902a6..887e3494b49e 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt @@ -28,7 +28,6 @@ import com.android.systemui.compose.modifiers.sysuiResTag import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor import com.android.systemui.keyguard.ui.composable.blueprint.ComposableLockscreenSceneBlueprint import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel -import javax.inject.Inject /** * Renders the content of the lockscreen. diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt index cf2e895b044b..e6132c6a2a59 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt @@ -169,6 +169,7 @@ fun SceneScope.NotificationScrollingStack( viewModel: NotificationsPlaceholderViewModel, maxScrimTop: () -> Float, shouldPunchHoleBehindScrim: Boolean, + shouldFillMaxSize: Boolean = true, shadeMode: ShadeMode, modifier: Modifier = Modifier, ) { @@ -327,14 +328,14 @@ fun SceneScope.NotificationScrollingStack( } Box( modifier = - Modifier.fillMaxSize() - .graphicsLayer { + Modifier.graphicsLayer { alpha = if (shouldPunchHoleBehindScrim) { (expansionFraction / EXPANSION_FOR_MAX_SCRIM_ALPHA).coerceAtMost(1f) } else 1f } .background(MaterialTheme.colorScheme.surface) + .thenIf(shouldFillMaxSize) { Modifier.fillMaxSize() } .debugBackground(viewModel, DEBUG_BOX_COLOR) ) { NotificationPlaceholder( diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt index e17a1464a71a..ae53d56e331a 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt @@ -17,21 +17,31 @@ package com.android.systemui.notifications.ui.composable import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Text +import androidx.compose.foundation.layout.width import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.android.compose.animation.scene.SceneScope import com.android.compose.animation.scene.UserAction import com.android.compose.animation.scene.UserActionResult +import com.android.systemui.battery.BatteryMeterViewController import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.ui.composable.LockscreenContent import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeSceneViewModel +import com.android.systemui.scene.session.ui.composable.SaveableSession import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.ui.composable.ComposableScene +import com.android.systemui.shade.shared.model.ShadeMode +import com.android.systemui.shade.ui.composable.ExpandedShadeHeader import com.android.systemui.shade.ui.composable.OverlayShade import com.android.systemui.shade.ui.viewmodel.OverlayShadeViewModel +import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel +import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView +import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel +import com.android.systemui.statusbar.phone.ui.StatusBarIconController +import com.android.systemui.statusbar.phone.ui.TintedIconManager import dagger.Lazy import java.util.Optional import javax.inject.Inject @@ -41,36 +51,53 @@ import kotlinx.coroutines.flow.StateFlow class NotificationsShadeScene @Inject constructor( - viewModel: NotificationsShadeSceneViewModel, + sceneViewModel: NotificationsShadeSceneViewModel, private val overlayShadeViewModel: OverlayShadeViewModel, + private val shadeHeaderViewModel: ShadeHeaderViewModel, + private val notificationsPlaceholderViewModel: NotificationsPlaceholderViewModel, + private val tintedIconManagerFactory: TintedIconManager.Factory, + private val batteryMeterViewControllerFactory: BatteryMeterViewController.Factory, + private val statusBarIconController: StatusBarIconController, + private val shadeSession: SaveableSession, + private val stackScrollView: Lazy<NotificationScrollView>, private val lockscreenContent: Lazy<Optional<LockscreenContent>>, ) : ComposableScene { override val key = Scenes.NotificationsShade override val destinationScenes: StateFlow<Map<UserAction, UserActionResult>> = - viewModel.destinationScenes + sceneViewModel.destinationScenes @Composable override fun SceneScope.Content( modifier: Modifier, ) { OverlayShade( - viewModel = overlayShadeViewModel, modifier = modifier, + viewModel = overlayShadeViewModel, horizontalArrangement = Arrangement.Start, lockscreenContent = lockscreenContent, ) { - Text( - text = "Notifications list", - modifier = Modifier.padding(NotificationsShade.Dimensions.Padding) - ) - } - } -} + Column { + ExpandedShadeHeader( + viewModel = shadeHeaderViewModel, + createTintedIconManager = tintedIconManagerFactory::create, + createBatteryMeterViewController = batteryMeterViewControllerFactory::create, + statusBarIconController = statusBarIconController, + modifier = Modifier.padding(horizontal = 16.dp), + ) -object NotificationsShade { - object Dimensions { - val Padding = 16.dp + NotificationScrollingStack( + shadeSession = shadeSession, + stackScrollView = stackScrollView.get(), + viewModel = notificationsPlaceholderViewModel, + maxScrimTop = { 0f }, + shouldPunchHoleBehindScrim = false, + shouldFillMaxSize = false, + shadeMode = ShadeMode.Dual, + modifier = Modifier.width(416.dp), + ) + } + } } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt index 04f76f5d58ab..4d946bff63ca 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt @@ -33,9 +33,9 @@ import com.android.systemui.scene.ui.composable.ComposableScene import com.android.systemui.shade.ui.composable.OverlayShade import com.android.systemui.shade.ui.viewmodel.OverlayShadeViewModel import dagger.Lazy +import java.util.Optional import javax.inject.Inject import kotlinx.coroutines.flow.StateFlow -import java.util.Optional @SysUISingleton class QuickSettingsShadeScene diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt index ce4032aaea05..bebfd859f9ed 100644 --- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt +++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt @@ -16,7 +16,6 @@ package com.android.keyguard.logging -import android.hardware.biometrics.BiometricSourceType import com.android.systemui.biometrics.AuthRippleController import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController import com.android.systemui.log.LogBuffer @@ -81,6 +80,23 @@ constructor( ) } + fun delayShowingTrustAgentError( + msg: CharSequence, + fpEngaged: Boolean, + faceRunning: Boolean, + ) { + buffer.log( + BIO_TAG, + LogLevel.DEBUG, + { + str1 = msg.toString() + bool1 = fpEngaged + bool2 = faceRunning + }, + { "Delay showing trustAgentError:$str1. fpEngaged:$bool1 faceRunning:$bool2 " } + ) + } + fun logUpdateDeviceEntryIndication( animate: Boolean, visible: Boolean, @@ -118,10 +134,9 @@ constructor( ) } - fun logDropNonFingerprintMessage( + fun logDropFaceMessage( message: CharSequence, followUpMessage: CharSequence?, - biometricSourceType: BiometricSourceType?, ) { buffer.log( KeyguardIndicationController.TAG, @@ -129,12 +144,8 @@ constructor( { str1 = message.toString() str2 = followUpMessage?.toString() - str3 = biometricSourceType?.name }, - { - "droppingNonFingerprintMessage message=$str1 " + - "followUpMessage:$str2 biometricSourceType:$str3" - } + { "droppingFaceMessage message=$str1 followUpMessage:$str2" } ) } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/UdfpsTouchOverlayBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/UdfpsTouchOverlayBinder.kt index 2e29c3b59c4c..7503a8b4362d 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/UdfpsTouchOverlayBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/UdfpsTouchOverlayBinder.kt @@ -46,15 +46,22 @@ object UdfpsTouchOverlayBinder { view.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.CREATED) { launch { - viewModel.shouldHandleTouches.collect { shouldHandleTouches -> + viewModel.shouldHandleTouches.collect { shouldHandleTouches -> + Log.d( + "UdfpsTouchOverlayBinder", + "[$view]: update shouldHandleTouches=$shouldHandleTouches" + ) + view.isInvisible = !shouldHandleTouches + udfpsOverlayInteractor.setHandleTouches(shouldHandleTouches) + } + } + .invokeOnCompletion { Log.d( "UdfpsTouchOverlayBinder", - "[$view]: update shouldHandleTouches=$shouldHandleTouches" + "[$view-detached]: update shouldHandleTouches=false" ) - view.isInvisible = !shouldHandleTouches - udfpsOverlayInteractor.setHandleTouches(shouldHandleTouches) + udfpsOverlayInteractor.setHandleTouches(false) } - } } } } diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFingerprintAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFingerprintAuthInteractor.kt index ec574d2d031d..a5eafa9d9025 100644 --- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFingerprintAuthInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFingerprintAuthInteractor.kt @@ -28,6 +28,7 @@ import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticati import javax.inject.Inject import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.flatMapLatest @@ -43,9 +44,15 @@ constructor( biometricSettingsInteractor: DeviceEntryBiometricSettingsInteractor, fingerprintPropertyRepository: FingerprintPropertyRepository, ) { - /** Whether fingerprint authentication is currently running or not */ + /** + * Whether fingerprint authentication is currently running or not. This does not mean the user + * [isEngaged] with the fingerprint. + */ val isRunning: Flow<Boolean> = repository.isRunning + /** Whether the user is actively engaging with the fingerprint sensor */ + val isEngaged: StateFlow<Boolean> = repository.isEngaged + /** Provide the current status of fingerprint authentication. */ val authenticationStatus: Flow<FingerprintAuthenticationStatus> = repository.authenticationStatus diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt index 0ebc92ed1c03..b1589dadb300 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt @@ -40,9 +40,13 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.SharingStarted.Companion.WhileSubscribed +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.buffer +import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.shareIn import kotlinx.coroutines.flow.stateIn @@ -57,6 +61,9 @@ interface DeviceEntryFingerprintAuthRepository { */ val isRunning: Flow<Boolean> + /** Whether the fingerprint sensor is actively authenticating. */ + val isEngaged: StateFlow<Boolean> + /** * Fingerprint sensor type present on the device, null if fingerprint sensor is not available. */ @@ -176,6 +183,17 @@ constructor( mainDispatcher ) // keyguardUpdateMonitor requires registration on main thread. + override val isEngaged: StateFlow<Boolean> = + authenticationStatus + .map { it.isEngaged } + .filterNotNull() + .map { it } + .stateIn( + scope = scope, + started = WhileSubscribed(), + initialValue = false, + ) + // TODO(b/322555228) Remove after consolidating device entry auth messages with BP auth messages // in BiometricStatusRepository /** diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FingerprintAuthenticationModels.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FingerprintAuthenticationModels.kt index d8b7b4a6a3d4..e92dec0c7163 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FingerprintAuthenticationModels.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FingerprintAuthenticationModels.kt @@ -19,6 +19,7 @@ package com.android.systemui.keyguard.shared.model import android.hardware.biometrics.BiometricFingerprintConstants import android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD import android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_START +import android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_UNKNOWN import android.hardware.fingerprint.FingerprintManager import android.os.SystemClock.elapsedRealtime import com.android.systemui.biometrics.shared.model.AuthenticationReason @@ -26,26 +27,43 @@ import com.android.systemui.biometrics.shared.model.AuthenticationReason /** * Fingerprint authentication status provided by * [com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository] + * + * @isEngaged whether fingerprint is actively engaged by the user. This is distinct from fingerprint + * running on the device. Can be null if the status does not have an associated isEngaged state. */ -sealed class FingerprintAuthenticationStatus +sealed class FingerprintAuthenticationStatus(val isEngaged: Boolean?) /** Fingerprint authentication success status. */ data class SuccessFingerprintAuthenticationStatus( val userId: Int, val isStrongBiometric: Boolean, -) : FingerprintAuthenticationStatus() +) : FingerprintAuthenticationStatus(isEngaged = false) /** Fingerprint authentication help message. */ data class HelpFingerprintAuthenticationStatus( val msgId: Int, val msg: String?, -) : FingerprintAuthenticationStatus() +) : FingerprintAuthenticationStatus(isEngaged = null) /** Fingerprint acquired message. */ data class AcquiredFingerprintAuthenticationStatus( val authenticationReason: AuthenticationReason, val acquiredInfo: Int -) : FingerprintAuthenticationStatus() { +) : + FingerprintAuthenticationStatus( + isEngaged = + if (acquiredInfo == FINGERPRINT_ACQUIRED_START) { + true + } else if ( + acquiredInfo == FINGERPRINT_ACQUIRED_UNKNOWN || + acquiredInfo == FINGERPRINT_ACQUIRED_GOOD + ) { + null + } else { + // soft errors that indicate fingerprint activity ended + false + } + ) { val fingerprintCaptureStarted: Boolean = acquiredInfo == FINGERPRINT_ACQUIRED_START @@ -53,7 +71,8 @@ data class AcquiredFingerprintAuthenticationStatus( } /** Fingerprint authentication failed message. */ -data object FailFingerprintAuthenticationStatus : FingerprintAuthenticationStatus() +data object FailFingerprintAuthenticationStatus : + FingerprintAuthenticationStatus(isEngaged = false) /** Fingerprint authentication error message */ data class ErrorFingerprintAuthenticationStatus( @@ -61,7 +80,7 @@ data class ErrorFingerprintAuthenticationStatus( val msg: String? = null, // present to break equality check if the same error occurs repeatedly. val createdAt: Long = elapsedRealtime(), -) : FingerprintAuthenticationStatus() { +) : FingerprintAuthenticationStatus(isEngaged = false) { fun isCancellationError(): Boolean = msgId == BiometricFingerprintConstants.FINGERPRINT_ERROR_CANCELED || msgId == BiometricFingerprintConstants.FINGERPRINT_ERROR_USER_CANCELED diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java index 4c60090743fd..01adab306ed1 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java @@ -223,7 +223,8 @@ public class ScreenshotController { private Bitmap mScreenBitmap; private SaveImageInBackgroundTask mSaveInBgTask; private boolean mScreenshotTakenInPortrait; - private boolean mBlockAttach; + private boolean mAttachRequested; + private boolean mDetachRequested; private Animator mScreenshotAnimation; private RequestCallback mCurrentRequestCallback; private ScreenshotActionsProvider mActionsProvider; @@ -672,7 +673,7 @@ public class ScreenshotController { () -> { final Intent intent = ActionIntentCreator.INSTANCE.createLongScreenshotIntent( owner, mContext); - mActionIntentExecutor.launchIntentAsync(intent, owner, true, null, null); + mContext.startActivity(intent); }, mViewProxy::restoreNonScrollingUi, mViewProxy::startLongScreenshotTransition); @@ -687,7 +688,7 @@ public class ScreenshotController { new ViewTreeObserver.OnWindowAttachListener() { @Override public void onWindowAttached() { - mBlockAttach = false; + mAttachRequested = false; decorView.getViewTreeObserver().removeOnWindowAttachListener(this); action.run(); } @@ -703,13 +704,13 @@ public class ScreenshotController { @MainThread private void attachWindow() { View decorView = mWindow.getDecorView(); - if (decorView.isAttachedToWindow() || mBlockAttach) { + if (decorView.isAttachedToWindow() || mAttachRequested) { return; } if (DEBUG_WINDOW) { Log.d(TAG, "attachWindow"); } - mBlockAttach = true; + mAttachRequested = true; mWindowManager.addView(decorView, mWindowLayoutParams); decorView.requestApplyInsets(); @@ -727,6 +728,11 @@ public class ScreenshotController { Log.d(TAG, "Removing screenshot window"); } mWindowManager.removeViewImmediate(decorView); + mDetachRequested = false; + } + if (mAttachRequested && !mDetachRequested) { + mDetachRequested = true; + withWindowAttached(this::removeWindow); } mViewProxy.stopInputListening(); diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt index 53c10a370868..fe16fc03ce40 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt @@ -49,11 +49,13 @@ constructor( sharedNotificationContainerInteractor: SharedNotificationContainerInteractor, shadeRepository: ShadeRepository, ) : BaseShadeInteractor { + override val shadeMode: StateFlow<ShadeMode> = shadeRepository.shadeMode + override val shadeExpansion: StateFlow<Float> = - sceneBasedExpansion(sceneInteractor, Scenes.Shade) + sceneBasedExpansion(sceneInteractor, notificationsScene) .stateIn(scope, SharingStarted.Eagerly, 0f) - private val sceneBasedQsExpansion = sceneBasedExpansion(sceneInteractor, Scenes.QuickSettings) + private val sceneBasedQsExpansion = sceneBasedExpansion(sceneInteractor, quickSettingsScene) override val qsExpansion: StateFlow<Float> = combine( @@ -81,7 +83,7 @@ constructor( when (state) { is ObservableTransitionState.Idle -> false is ObservableTransitionState.Transition -> - state.toScene == Scenes.QuickSettings && state.fromScene != Scenes.Shade + state.toScene == quickSettingsScene && state.fromScene != notificationsScene } } .distinctUntilChanged() @@ -90,7 +92,7 @@ constructor( sceneInteractor.transitionState .map { state -> when (state) { - is ObservableTransitionState.Idle -> state.currentScene == Scenes.QuickSettings + is ObservableTransitionState.Idle -> state.currentScene == quickSettingsScene is ObservableTransitionState.Transition -> false } } @@ -106,12 +108,10 @@ constructor( .stateIn(scope, SharingStarted.Eagerly, false) override val isUserInteractingWithShade: Flow<Boolean> = - sceneBasedInteracting(sceneInteractor, Scenes.Shade) + sceneBasedInteracting(sceneInteractor, notificationsScene) override val isUserInteractingWithQs: Flow<Boolean> = - sceneBasedInteracting(sceneInteractor, Scenes.QuickSettings) - - override val shadeMode: StateFlow<ShadeMode> = shadeRepository.shadeMode + sceneBasedInteracting(sceneInteractor, quickSettingsScene) /** * Returns a flow that uses scene transition progress to and from a scene that is pulled down @@ -154,4 +154,20 @@ constructor( } } .distinctUntilChanged() + + private val notificationsScene: SceneKey + get() = + if (shadeMode.value is ShadeMode.Dual) { + Scenes.NotificationsShade + } else { + Scenes.Shade + } + + private val quickSettingsScene: SceneKey + get() = + if (shadeMode.value is ShadeMode.Dual) { + Scenes.QuickSettingsShade + } else { + Scenes.QuickSettings + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java index 8d8a36acc2a2..47939ae07539 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java @@ -98,6 +98,8 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.deviceentry.domain.interactor.BiometricMessageInteractor; +import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor; +import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFingerprintAuthInteractor; import com.android.systemui.dock.DockManager; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.keyguard.KeyguardIndication; @@ -183,11 +185,14 @@ public class KeyguardIndicationController { private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; private KeyguardInteractor mKeyguardInteractor; private final BiometricMessageInteractor mBiometricMessageInteractor; + private DeviceEntryFingerprintAuthInteractor mDeviceEntryFingerprintAuthInteractor; + private DeviceEntryFaceAuthInteractor mDeviceEntryFaceAuthInteractor; private String mPersistentUnlockMessage; private String mAlignmentIndication; private boolean mForceIsDismissible; private CharSequence mTrustGrantedIndication; private CharSequence mTransientIndication; + private CharSequence mTrustAgentErrorMessage; private CharSequence mBiometricMessage; private CharSequence mBiometricMessageFollowUp; private BiometricSourceType mBiometricMessageSource; @@ -235,6 +240,13 @@ public class KeyguardIndicationController { final Consumer<Set<Integer>> mCoExAcquisitionMsgIdsToShowCallback = (Set<Integer> coExFaceAcquisitionMsgIdsToShow) -> mCoExFaceAcquisitionMsgIdsToShow = coExFaceAcquisitionMsgIdsToShow; + @VisibleForTesting + final Consumer<Boolean> mIsFingerprintEngagedCallback = + (Boolean isEngaged) -> { + if (!isEngaged) { + showTrustAgentErrorMessage(mTrustAgentErrorMessage); + } + }; private final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() { @Override public void onScreenTurnedOn() { @@ -295,7 +307,9 @@ public class KeyguardIndicationController { FeatureFlags flags, IndicationHelper indicationHelper, KeyguardInteractor keyguardInteractor, - BiometricMessageInteractor biometricMessageInteractor + BiometricMessageInteractor biometricMessageInteractor, + DeviceEntryFingerprintAuthInteractor deviceEntryFingerprintAuthInteractor, + DeviceEntryFaceAuthInteractor deviceEntryFaceAuthInteractor ) { mContext = context; mBroadcastDispatcher = broadcastDispatcher; @@ -325,6 +339,8 @@ public class KeyguardIndicationController { mIndicationHelper = indicationHelper; mKeyguardInteractor = keyguardInteractor; mBiometricMessageInteractor = biometricMessageInteractor; + mDeviceEntryFingerprintAuthInteractor = deviceEntryFingerprintAuthInteractor; + mDeviceEntryFaceAuthInteractor = deviceEntryFaceAuthInteractor; mFaceAcquiredMessageDeferral = faceHelpMessageDeferral.create(); @@ -409,6 +425,8 @@ public class KeyguardIndicationController { collectFlow(mIndicationArea, mBiometricMessageInteractor.getCoExFaceAcquisitionMsgIdsToShow(), mCoExAcquisitionMsgIdsToShowCallback); + collectFlow(mIndicationArea, mDeviceEntryFingerprintAuthInteractor.isEngaged(), + mIsFingerprintEngagedCallback); } /** @@ -944,19 +962,25 @@ public class KeyguardIndicationController { if (!isSuccessMessage && mBiometricMessageSource == FINGERPRINT - && biometricSourceType != FINGERPRINT) { - // drop all non-fingerprint biometric messages if there's a fingerprint message showing - mKeyguardLogger.logDropNonFingerprintMessage( + && biometricSourceType == FACE) { + // drop any face messages if there's a fingerprint message showing + mKeyguardLogger.logDropFaceMessage( biometricMessage, - biometricMessageFollowUp, - biometricSourceType + biometricMessageFollowUp ); return; } - mBiometricMessage = biometricMessage; - mBiometricMessageFollowUp = biometricMessageFollowUp; - mBiometricMessageSource = biometricSourceType; + if (mBiometricMessageSource != null && biometricSourceType == null) { + // If there's a current biometric message showing and a non-biometric message + // arrives, update the followup message with the non-biometric message. + // Keep the biometricMessage and biometricMessageSource the same. + mBiometricMessageFollowUp = biometricMessage; + } else { + mBiometricMessage = biometricMessage; + mBiometricMessageFollowUp = biometricMessageFollowUp; + mBiometricMessageSource = biometricSourceType; + } mHandler.removeMessages(MSG_SHOW_ACTION_TO_UNLOCK); hideBiometricMessageDelayed( @@ -1455,7 +1479,7 @@ public class KeyguardIndicationController { @Override public void onTrustAgentErrorMessage(CharSequence message) { - showBiometricMessage(message, null); + showTrustAgentErrorMessage(message); } @Override @@ -1467,6 +1491,10 @@ public class KeyguardIndicationController { hideBiometricMessage(); mBiometricErrorMessageToShowOnScreenOn = null; } + + if (!running && biometricSourceType == FACE) { + showTrustAgentErrorMessage(mTrustAgentErrorMessage); + } } @Override @@ -1533,6 +1561,25 @@ public class KeyguardIndicationController { return getCurrentUser() == userId; } + /** + * Only show trust agent messages after biometrics are no longer active. + */ + private void showTrustAgentErrorMessage(CharSequence message) { + if (message == null) { + mTrustAgentErrorMessage = null; + return; + } + boolean fpEngaged = mDeviceEntryFingerprintAuthInteractor.isEngaged().getValue(); + boolean faceRunning = mDeviceEntryFaceAuthInteractor.isRunning(); + if (fpEngaged || faceRunning) { + mKeyguardLogger.delayShowingTrustAgentError(message, fpEngaged, faceRunning); + mTrustAgentErrorMessage = message; + } else { + mTrustAgentErrorMessage = null; + showBiometricMessage(message, null); + } + } + protected void showTrustGrantedMessage(boolean dismissKeyguard, @Nullable String message) { mTrustGrantedIndication = message; updateDeviceEntryIndication(false); @@ -1639,6 +1686,7 @@ public class KeyguardIndicationController { new KeyguardStateController.Callback() { @Override public void onUnlockedChanged() { + mTrustAgentErrorMessage = null; updateDeviceEntryIndication(false); } @@ -1649,6 +1697,7 @@ public class KeyguardIndicationController { mKeyguardLogger.log(TAG, LogLevel.DEBUG, "clear messages"); mTopIndicationView.clearMessages(); mRotateTextViewController.clearMessages(); + mTrustAgentErrorMessage = null; } else { updateDeviceEntryIndication(false); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt index 61373815db1c..c2ce1144fe1b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification.stack.ui.viewmodel import com.android.compose.animation.scene.ObservableTransitionState +import com.android.compose.animation.scene.SceneKey import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dump.DumpManager import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor @@ -25,6 +26,7 @@ import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.domain.interactor.ShadeInteractor +import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationStackAppearanceInteractor import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimClipping import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimShape @@ -34,6 +36,7 @@ import com.android.systemui.util.kotlin.FlowDumperImpl import dagger.Lazy import javax.inject.Inject import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flowOf @@ -73,16 +76,16 @@ constructor( } is ObservableTransitionState.Transition -> { if ( - (transitionState.fromScene == Scenes.Shade && - transitionState.toScene == Scenes.QuickSettings) || - (transitionState.fromScene == Scenes.QuickSettings && - transitionState.toScene == Scenes.Shade) + (transitionState.fromScene == notificationsScene && + transitionState.toScene == quickSettingsScene) || + (transitionState.fromScene == quickSettingsScene && + transitionState.toScene == notificationsScene) ) { 1f } else if ( (transitionState.fromScene == Scenes.Gone || transitionState.fromScene == Scenes.Lockscreen) && - transitionState.toScene == Scenes.QuickSettings + transitionState.toScene == quickSettingsScene ) { // during QS expansion, increase fraction at same rate as scrim alpha, // but start when scrim alpha is at EXPANSION_FOR_DELAYED_STACK_FADE_IN. @@ -152,7 +155,9 @@ constructor( /** Whether the notification stack is scrollable or not. */ val isScrollable: Flow<Boolean> = - sceneInteractor.currentScene.map { it == Scenes.Shade }.dumpWhileCollecting("isScrollable") + sceneInteractor.currentScene + .map { it == notificationsScene } + .dumpWhileCollecting("isScrollable") /** Whether the notification stack is displayed in doze mode. */ val isDozing: Flow<Boolean> by lazy { @@ -162,4 +167,22 @@ constructor( keyguardInteractor.get().isDozing.dumpWhileCollecting("isDozing") } } + + private val shadeMode: StateFlow<ShadeMode> = shadeInteractor.shadeMode + + private val notificationsScene: SceneKey + get() = + if (shadeMode.value is ShadeMode.Dual) { + Scenes.NotificationsShade + } else { + Scenes.Shade + } + + private val quickSettingsScene: SceneKey + get() = + if (shadeMode.value is ShadeMode.Dual) { + Scenes.QuickSettingsShade + } else { + Scenes.QuickSettings + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt index 12f252d215a9..9d9cc2aa11de 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt @@ -17,6 +17,8 @@ package com.android.systemui.statusbar.pipeline.satellite.data.prod import android.os.OutcomeReceiver +import android.telephony.TelephonyCallback +import android.telephony.TelephonyManager import android.telephony.satellite.NtnSignalStrengthCallback import android.telephony.satellite.SatelliteManager import android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS @@ -38,6 +40,7 @@ import com.android.systemui.statusbar.pipeline.satellite.data.prod.SatelliteSupp import com.android.systemui.statusbar.pipeline.satellite.data.prod.SatelliteSupport.Unknown import com.android.systemui.statusbar.pipeline.satellite.shared.model.SatelliteConnectionState import com.android.systemui.util.kotlin.getOrNull +import com.android.systemui.util.kotlin.pairwise import com.android.systemui.util.time.SystemClock import java.util.Optional import javax.inject.Inject @@ -51,12 +54,15 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.mapNotNull +import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import kotlinx.coroutines.suspendCancellableCoroutine @@ -92,13 +98,19 @@ sealed interface SatelliteSupport { @OptIn(ExperimentalCoroutinesApi::class) companion object { - /** Convenience function to switch to the supported flow */ + /** + * Convenience function to switch to the supported flow. [retrySignal] is a flow that emits + * [Unit] whenever the [supported] flow needs to be restarted + */ fun <T> Flow<SatelliteSupport>.whenSupported( supported: (SatelliteManager) -> Flow<T>, orElse: Flow<T>, - ): Flow<T> = flatMapLatest { - when (it) { - is Supported -> supported(it.satelliteManager) + retrySignal: Flow<Unit>, + ): Flow<T> = flatMapLatest { satelliteSupport -> + when (satelliteSupport) { + is Supported -> { + retrySignal.flatMapLatest { supported(satelliteSupport.satelliteManager) } + } else -> orElse } } @@ -132,6 +144,7 @@ class DeviceBasedSatelliteRepositoryImpl @Inject constructor( satelliteManagerOpt: Optional<SatelliteManager>, + telephonyManager: TelephonyManager, @Background private val bgDispatcher: CoroutineDispatcher, @Application private val scope: CoroutineScope, @OemSatelliteInputLog private val logBuffer: LogBuffer, @@ -201,11 +214,65 @@ constructor( } } + /** + * Note that we are given an "unbound" [TelephonyManager] (meaning it was not created with a + * specific `subscriptionId`). Therefore this is the radio power state of the + * DEFAULT_SUBSCRIPTION_ID subscription. This subscription, I am led to believe, is the one that + * would be used for the SatelliteManager subscription. + * + * By watching power state changes, we can detect if the telephony process crashes. + * + * See b/337258696 for details + */ + private val radioPowerState: StateFlow<Int> = + conflatedCallbackFlow { + val cb = + object : TelephonyCallback(), TelephonyCallback.RadioPowerStateListener { + override fun onRadioPowerStateChanged(powerState: Int) { + trySend(powerState) + } + } + + telephonyManager.registerTelephonyCallback(bgDispatcher.asExecutor(), cb) + + awaitClose { telephonyManager.unregisterTelephonyCallback(cb) } + } + .flowOn(bgDispatcher) + .stateIn( + scope, + SharingStarted.WhileSubscribed(), + TelephonyManager.RADIO_POWER_UNAVAILABLE + ) + + /** + * In the event that a telephony phone process has crashed, we expect to see a radio power state + * change from ON to something else. This trigger can be used to re-start a flow via + * [whenSupported] + * + * This flow emits [Unit] when started so that newly-started collectors always run, and only + * restart when the state goes from ON -> !ON + */ + private val telephonyProcessCrashedEvent: Flow<Unit> = + radioPowerState + .pairwise() + .mapNotNull { (prev: Int, new: Int) -> + if ( + prev == TelephonyManager.RADIO_POWER_ON && + new != TelephonyManager.RADIO_POWER_ON + ) { + Unit + } else { + null + } + } + .onStart { emit(Unit) } + override val connectionState = satelliteSupport .whenSupported( supported = ::connectionStateFlow, - orElse = flowOf(SatelliteConnectionState.Off) + orElse = flowOf(SatelliteConnectionState.Off), + retrySignal = telephonyProcessCrashedEvent, ) .stateIn(scope, SharingStarted.Eagerly, SatelliteConnectionState.Off) @@ -232,7 +299,11 @@ constructor( override val signalStrength = satelliteSupport - .whenSupported(supported = ::signalStrengthFlow, orElse = flowOf(0)) + .whenSupported( + supported = ::signalStrengthFlow, + orElse = flowOf(0), + retrySignal = telephonyProcessCrashedEvent, + ) .stateIn(scope, SharingStarted.Eagerly, 0) // By using the SupportedSatelliteManager here, we expect registration never to fail diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerBaseTest.java index fe066ca2c318..59678a2f8c90 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerBaseTest.java @@ -20,14 +20,19 @@ import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT; import static com.android.systemui.flags.Flags.KEYGUARD_TALKBACK_FIX; import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED; +import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_TRANSIENT; import static com.android.systemui.keyguard.ScreenLifecycle.SCREEN_ON; +import static com.google.common.truth.Truth.assertThat; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -65,6 +70,8 @@ import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.deviceentry.domain.interactor.BiometricMessageInteractor; +import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor; +import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFingerprintAuthInteractor; import com.android.systemui.dock.DockManager; import com.android.systemui.flags.FakeFeatureFlags; import com.android.systemui.keyguard.KeyguardIndication; @@ -150,6 +157,10 @@ public class KeyguardIndicationControllerBaseTest extends SysuiTestCase { @Mock protected BiometricMessageInteractor mBiometricMessageInteractor; @Mock + protected DeviceEntryFaceAuthInteractor mDeviceEntryFaceAuthInteractor; + @Mock + protected DeviceEntryFingerprintAuthInteractor mDeviceEntryFingerprintAuthInteractor; + @Mock protected ScreenLifecycle mScreenLifecycle; @Mock protected AuthController mAuthController; @@ -237,6 +248,7 @@ public class KeyguardIndicationControllerBaseTest extends SysuiTestCase { .thenReturn(mock(StateFlow.class)); when(mFaceHelpMessageDeferralFactory.create()).thenReturn(mFaceHelpMessageDeferral); + when(mDeviceEntryFingerprintAuthInteractor.isEngaged()).thenReturn(mock(StateFlow.class)); mIndicationHelper = new IndicationHelper(mKeyguardUpdateMonitor); @@ -279,7 +291,9 @@ public class KeyguardIndicationControllerBaseTest extends SysuiTestCase { mFlags, mIndicationHelper, KeyguardInteractorFactory.create(mFlags).getKeyguardInteractor(), - mBiometricMessageInteractor + mBiometricMessageInteractor, + mDeviceEntryFingerprintAuthInteractor, + mDeviceEntryFaceAuthInteractor ); mController.init(); mController.setIndicationArea(mIndicationArea); @@ -306,4 +320,22 @@ public class KeyguardIndicationControllerBaseTest extends SysuiTestCase { mExecutor.runAllReady(); reset(mRotateTextViewController); } + + void verifyNoMessage(int type) { + if (type == INDICATION_TYPE_TRANSIENT) { + verify(mRotateTextViewController, never()).showTransient(anyString()); + } else { + verify(mRotateTextViewController, never()).updateIndication(eq(type), + any(KeyguardIndication.class), anyBoolean()); + } + } + + void verifyIndicationShown(int indicationType, String message) { + verify(mRotateTextViewController) + .updateIndication(eq(indicationType), + mKeyguardIndicationCaptor.capture(), + eq(true)); + assertThat(mKeyguardIndicationCaptor.getValue().getMessage().toString()) + .isEqualTo(message); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java index cfe9e2ab7bb6..80011dcab1cd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java @@ -1514,19 +1514,6 @@ public class KeyguardIndicationControllerTest extends KeyguardIndicationControll } @Test - public void onTrustAgentErrorMessageDroppedBecauseFingerprintMessageShowing() { - createController(); - mController.setVisible(true); - mController.getKeyguardCallback().onBiometricHelp(BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED, - "fp not recognized", BiometricSourceType.FINGERPRINT); - clearInvocations(mRotateTextViewController); - - mKeyguardUpdateMonitorCallback.onTrustAgentErrorMessage("testMessage"); - verifyNoMessage(INDICATION_TYPE_TRUST); - verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE); - } - - @Test public void trustGrantedMessageShowsEvenWhenFingerprintMessageShowing() { createController(); mController.setVisible(true); @@ -1591,24 +1578,6 @@ public class KeyguardIndicationControllerTest extends KeyguardIndicationControll verify(mRotateTextViewController).showTransient(eq(message)); } - private void verifyNoMessage(int type) { - if (type == INDICATION_TYPE_TRANSIENT) { - verify(mRotateTextViewController, never()).showTransient(anyString()); - } else { - verify(mRotateTextViewController, never()).updateIndication(eq(type), - anyObject(), anyBoolean()); - } - } - - private void verifyIndicationShown(int indicationType, String message) { - verify(mRotateTextViewController) - .updateIndication(eq(indicationType), - mKeyguardIndicationCaptor.capture(), - eq(true)); - assertThat(mKeyguardIndicationCaptor.getValue().getMessage().toString()) - .isEqualTo(message); - } - private void fingerprintUnlockIsNotPossible() { setupFingerprintUnlockPossible(false); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerWithCoroutinesTest.kt index 4a14f8853904..a68ba06637cc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerWithCoroutinesTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerWithCoroutinesTest.kt @@ -21,12 +21,17 @@ import android.view.View import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED +import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BIOMETRIC_MESSAGE +import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP +import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_TRUST import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.runBlocking import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.times import org.mockito.Mockito.verify +import org.mockito.kotlin.whenever @RunWith(AndroidJUnit4::class) @SmallTest @@ -62,6 +67,33 @@ class KeyguardIndicationControllerWithCoroutinesTest : KeyguardIndicationControl verify(mIndicationArea, times(3)).visibility = View.VISIBLE } + @Test + fun onTrustAgentErrorMessageDelayed_fingerprintEngaged() { + createController() + mController.setVisible(true) + + // GIVEN fingerprint is engaged + whenever(mDeviceEntryFingerprintAuthInteractor.isEngaged).thenReturn(MutableStateFlow(true)) + + // WHEN a trust agent error message arrives + mKeyguardUpdateMonitorCallback.onTrustAgentErrorMessage("testMessage") + mExecutor.runAllReady() + + // THEN no message shows immediately since fingerprint is engaged + verifyNoMessage(INDICATION_TYPE_TRUST) + verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE) + verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP) + + // WHEN fingerprint is no longer engaged + whenever(mDeviceEntryFingerprintAuthInteractor.isEngaged) + .thenReturn(MutableStateFlow(false)) + mController.mIsFingerprintEngagedCallback.accept(false) + mExecutor.runAllReady() + + // THEN the message will show + verifyIndicationShown(INDICATION_TYPE_BIOMETRIC_MESSAGE, "testMessage") + } + companion object { private val IMMEDIATE = Dispatchers.Main.immediate } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepositorySwitcherTest.kt index 7ca3b1c425d3..6300953c86b7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepositorySwitcherTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepositorySwitcherTest.kt @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.pipeline.satellite.data +import android.telephony.TelephonyManager import android.telephony.satellite.SatelliteManager import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase @@ -50,11 +51,13 @@ class DeviceBasedSatelliteRepositorySwitcherTest : SysuiTestCase() { private val demoModeController = mock<DemoModeController>().apply { whenever(this.isInDemoMode).thenReturn(false) } private val satelliteManager = mock<SatelliteManager>() + private val telephonyManager = mock<TelephonyManager>() private val systemClock = FakeSystemClock() private val realImpl = DeviceBasedSatelliteRepositoryImpl( Optional.of(satelliteManager), + telephonyManager, testDispatcher, testScope.backgroundScope, FakeLogBuffer.Factory.create(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt index 6b0ad4bdb770..66516769c804 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt @@ -18,6 +18,8 @@ package com.android.systemui.statusbar.pipeline.satellite.data.prod import android.os.OutcomeReceiver import android.os.Process +import android.telephony.TelephonyCallback +import android.telephony.TelephonyManager import android.telephony.satellite.NtnSignalStrength import android.telephony.satellite.NtnSignalStrengthCallback import android.telephony.satellite.SatelliteManager @@ -36,6 +38,7 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.log.core.FakeLogBuffer +import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers import com.android.systemui.statusbar.pipeline.satellite.data.prod.DeviceBasedSatelliteRepositoryImpl.Companion.MIN_UPTIME import com.android.systemui.statusbar.pipeline.satellite.data.prod.DeviceBasedSatelliteRepositoryImpl.Companion.POLLING_INTERVAL_MS import com.android.systemui.statusbar.pipeline.satellite.shared.model.SatelliteConnectionState @@ -59,6 +62,7 @@ import org.mockito.Mock import org.mockito.Mockito import org.mockito.Mockito.doAnswer import org.mockito.Mockito.never +import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @@ -69,6 +73,7 @@ class DeviceBasedSatelliteRepositoryImplTest : SysuiTestCase() { private lateinit var underTest: DeviceBasedSatelliteRepositoryImpl @Mock private lateinit var satelliteManager: SatelliteManager + @Mock private lateinit var telephonyManager: TelephonyManager private val systemClock = FakeSystemClock() private val dispatcher = StandardTestDispatcher() @@ -86,6 +91,7 @@ class DeviceBasedSatelliteRepositoryImplTest : SysuiTestCase() { underTest = DeviceBasedSatelliteRepositoryImpl( Optional.empty(), + telephonyManager, dispatcher, testScope.backgroundScope, FakeLogBuffer.Factory.create(), @@ -362,6 +368,68 @@ class DeviceBasedSatelliteRepositoryImplTest : SysuiTestCase() { verify(satelliteManager).registerForModemStateChanged(any(), any()) } + @Test + fun telephonyCrash_repoReregistersConnectionStateListener() = + testScope.runTest { + setupDefaultRepo() + + // GIVEN connection state is requested + val connectionState by collectLastValue(underTest.connectionState) + + runCurrent() + + val telephonyCallback = + MobileTelephonyHelpers.getTelephonyCallbackForType< + TelephonyCallback.RadioPowerStateListener + >( + telephonyManager + ) + + // THEN listener is registered once + verify(satelliteManager, times(1)).registerForModemStateChanged(any(), any()) + + // WHEN a crash event happens (detected by radio state change) + telephonyCallback.onRadioPowerStateChanged(TelephonyManager.RADIO_POWER_ON) + runCurrent() + telephonyCallback.onRadioPowerStateChanged(TelephonyManager.RADIO_POWER_OFF) + runCurrent() + + // THEN listeners are unregistered and re-registered + verify(satelliteManager, times(1)).unregisterForModemStateChanged(any()) + verify(satelliteManager, times(2)).registerForModemStateChanged(any(), any()) + } + + @Test + fun telephonyCrash_repoReregistersSignalStrengthListener() = + testScope.runTest { + setupDefaultRepo() + + // GIVEN signal strength is requested + val signalStrength by collectLastValue(underTest.signalStrength) + + runCurrent() + + val telephonyCallback = + MobileTelephonyHelpers.getTelephonyCallbackForType< + TelephonyCallback.RadioPowerStateListener + >( + telephonyManager + ) + + // THEN listeners are registered the first time + verify(satelliteManager, times(1)).registerForNtnSignalStrengthChanged(any(), any()) + + // WHEN a crash event happens (detected by radio state change) + telephonyCallback.onRadioPowerStateChanged(TelephonyManager.RADIO_POWER_ON) + runCurrent() + telephonyCallback.onRadioPowerStateChanged(TelephonyManager.RADIO_POWER_OFF) + runCurrent() + + // THEN listeners are unregistered and re-registered + verify(satelliteManager, times(1)).unregisterForNtnSignalStrengthChanged(any()) + verify(satelliteManager, times(2)).registerForNtnSignalStrengthChanged(any(), any()) + } + private fun setUpRepo( uptime: Long = MIN_UPTIME, satMan: SatelliteManager? = satelliteManager, @@ -380,6 +448,7 @@ class DeviceBasedSatelliteRepositoryImplTest : SysuiTestCase() { underTest = DeviceBasedSatelliteRepositoryImpl( if (satMan != null) Optional.of(satMan) else Optional.empty(), + telephonyManager, dispatcher, testScope.backgroundScope, FakeLogBuffer.Factory.create(), diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt index 93e0b418d076..d558c9654d9c 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt @@ -40,6 +40,9 @@ class FakeDeviceEntryFingerprintAuthRepository @Inject constructor() : private val _isRunning = MutableStateFlow(false) override val isRunning: Flow<Boolean> get() = _isRunning + + override val isEngaged: MutableStateFlow<Boolean> = MutableStateFlow(false) + fun setIsRunning(value: Boolean) { _isRunning.value = value } diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp index 95cbb6b2130a..48bc803f4a5c 100644 --- a/ravenwood/Android.bp +++ b/ravenwood/Android.bp @@ -56,11 +56,52 @@ java_library { visibility: ["//visibility:public"], } +// This and the next module contain the same classes with different implementations. +// "ravenwood-runtime-common-device" will be statically linked in device side tests. +// "ravenwood-runtime-common-ravenwood" will only exist in ravenwood-runtime, which will take +// precedence even if the test jar (accidentally) contains "ravenwood-runtime-common-device". +// "ravenwood-runtime-common" uses it to detect if the rutime is Ravenwood or not. +java_library { + name: "ravenwood-runtime-common-ravenwood", + host_supported: true, + sdk_version: "core_current", + srcs: [ + "runtime-common-ravenwood-src/**/*.java", + ], + visibility: ["//frameworks/base"], +} + +java_library { + name: "ravenwood-runtime-common-device", + host_supported: true, + sdk_version: "core_current", + srcs: [ + "runtime-common-device-src/**/*.java", + ], + visibility: ["//visibility:private"], +} + +java_library { + name: "ravenwood-runtime-common", + host_supported: true, + sdk_version: "core_current", + srcs: [ + "runtime-common-src/**/*.java", + ], + libs: [ + "ravenwood-runtime-common-ravenwood", + ], + visibility: ["//visibility:private"], +} + java_library_host { name: "ravenwood-helper-libcore-runtime.host", srcs: [ "runtime-helper-src/libcore-fake/**/*.java", ], + static_libs: [ + "ravenwood-runtime-common", + ], visibility: ["//visibility:private"], } @@ -77,6 +118,9 @@ java_library { srcs: [ "runtime-helper-src/framework/**/*.java", ], + static_libs: [ + "ravenwood-runtime-common", + ], libs: [ "framework-minus-apex.ravenwood", "ravenwood-junit", @@ -105,6 +149,7 @@ java_library { ], static_libs: [ "androidx.test.monitor-for-device", + "ravenwood-runtime-common", ], libs: [ "android.test.mock", @@ -145,6 +190,10 @@ java_library { "junit-flag-src/**/*.java", ], sdk_version: "test_current", + static_libs: [ + "ravenwood-runtime-common", + "ravenwood-runtime-common-device", + ], libs: [ "junit", "flag-junit", @@ -199,7 +248,7 @@ cc_library_shared { ], srcs: [ - "runtime-helper-src/jni/*.cpp", + "runtime-jni/*.cpp", ], shared_libs: [ diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java index 5506a46203d6..49e793fcbddf 100644 --- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java +++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java @@ -86,10 +86,6 @@ public class RavenwoodRuleImpl { sPendingUncaughtException.compareAndSet(null, throwable); }; - public static boolean isOnRavenwood() { - return true; - } - public static void init(RavenwoodRule rule) { if (ENABLE_UNCAUGHT_EXCEPTION_DETECTION) { maybeThrowPendingUncaughtException(false); diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java index 9d12f855c0ea..68b5aebe9c00 100644 --- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java +++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java @@ -29,6 +29,8 @@ import android.platform.test.annotations.DisabledOnRavenwood; import android.platform.test.annotations.EnabledOnRavenwood; import android.platform.test.annotations.IgnoreUnderRavenwood; +import com.android.ravenwood.common.RavenwoodCommonUtils; + import org.junit.Assume; import org.junit.rules.TestRule; import org.junit.runner.Description; @@ -54,7 +56,7 @@ import java.util.regex.Pattern; * before a test class is fully initialized. */ public class RavenwoodRule implements TestRule { - static final boolean IS_ON_RAVENWOOD = RavenwoodRuleImpl.isOnRavenwood(); + static final boolean IS_ON_RAVENWOOD = RavenwoodCommonUtils.isOnRavenwood(); /** * When probing is enabled, all tests will be unconditionally run on Ravenwood to detect diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java index c3786ee0041d..5f1b0c2c929f 100644 --- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java +++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java @@ -16,6 +16,8 @@ package android.platform.test.ravenwood; +import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_SYSPROP; + import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -101,6 +103,8 @@ public class RavenwoodSystemProperties { setValue("ro.soc.model", "Ravenwood"); setValue("ro.debuggable", "1"); + + setValue(RAVENWOOD_SYSPROP, "1"); } /** Copy constructor */ diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodUtils.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodUtils.java index 99ab32788235..19c1bffaebcd 100644 --- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodUtils.java +++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodUtils.java @@ -15,9 +15,7 @@ */ package android.platform.test.ravenwood; -import java.io.File; -import java.io.PrintStream; -import java.util.Arrays; +import com.android.ravenwood.common.RavenwoodCommonUtils; /** * Utilities for writing (bivalent) ravenwood tests. @@ -26,15 +24,6 @@ public class RavenwoodUtils { private RavenwoodUtils() { } - private static final String RAVENWOOD_NATIVE_RUNTIME_NAME = "ravenwood_runtime"; - - // LibcoreRavenwoodUtils calls it with reflections. - public static void loadRavenwoodNativeRuntime() { - if (RavenwoodRule.isOnRavenwood()) { - RavenwoodUtils.loadJniLibrary(RAVENWOOD_NATIVE_RUNTIME_NAME); - } - } - /** * Load a JNI library respecting {@code java.library.path} * (which reflects {@code LD_LIBRARY_PATH}). @@ -56,85 +45,6 @@ public class RavenwoodUtils { * it uses {@code JNI_OnLoad()} as the entry point name on both. */ public static void loadJniLibrary(String libname) { - if (RavenwoodRule.isOnRavenwood()) { - loadLibraryOnRavenwood(libname); - } else { - // Just delegate to the loadLibrary(). - System.loadLibrary(libname); - } - } - - private static void loadLibraryOnRavenwood(String libname) { - var path = System.getProperty("java.library.path"); - var filename = "lib" + libname + ".so"; - - System.out.println("Looking for library " + libname + ".so in java.library.path:" + path); - - try { - if (path == null) { - throw new UnsatisfiedLinkError("Cannot load library " + libname + "." - + " Property java.library.path not set!"); - } - for (var dir : path.split(":")) { - var file = new File(dir + "/" + filename); - if (file.exists()) { - System.load(file.getAbsolutePath()); - return; - } - } - throw new UnsatisfiedLinkError("Library " + libname + " not found in " - + "java.library.path: " + path); - } catch (Throwable e) { - dumpFiles(System.out); - throw e; - } - } - - private static void dumpFiles(PrintStream out) { - try { - var path = System.getProperty("java.library.path"); - out.println("# java.library.path=" + path); - - for (var dir : path.split(":")) { - listFiles(out, new File(dir), ""); - - var gparent = new File((new File(dir)).getAbsolutePath() + "../../..") - .getCanonicalFile(); - if (gparent.getName().contains("testcases")) { - // Special case: if we found this directory, dump its contents too. - listFiles(out, gparent, ""); - } - } - - var gparent = new File("../..").getCanonicalFile(); - out.println("# ../..=" + gparent); - listFiles(out, gparent, ""); - } catch (Throwable th) { - out.println("Error: " + th.toString()); - th.printStackTrace(out); - } - } - - private static void listFiles(PrintStream out, File dir, String prefix) { - if (!dir.isDirectory()) { - out.println(prefix + dir.getAbsolutePath() + " is not a directory!"); - return; - } - out.println(prefix + ":" + dir.getAbsolutePath() + "/"); - // First, list the files. - for (var file : Arrays.stream(dir.listFiles()).sorted().toList()) { - out.println(prefix + " " + file.getName() + "" + (file.isDirectory() ? "/" : "")); - } - - // Then recurse. - if (dir.getAbsolutePath().startsWith("/usr") || dir.getAbsolutePath().startsWith("/lib")) { - // There would be too many files, so don't recurse. - return; - } - for (var file : Arrays.stream(dir.listFiles()).sorted().toList()) { - if (file.isDirectory()) { - listFiles(out, file, prefix + " "); - } - } + RavenwoodCommonUtils.loadJniLibrary(libname); } } diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java b/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java index 773a89a3df4d..483b98a96034 100644 --- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java +++ b/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java @@ -20,10 +20,6 @@ import org.junit.runner.Description; import org.junit.runners.model.Statement; public class RavenwoodRuleImpl { - public static boolean isOnRavenwood() { - return false; - } - public static void init(RavenwoodRule rule) { // No-op when running on a real device } diff --git a/ravenwood/runtime-common-device-src/com/android/ravenwood/common/divergence/RavenwoodDivergence.java b/ravenwood/runtime-common-device-src/com/android/ravenwood/common/divergence/RavenwoodDivergence.java new file mode 100644 index 000000000000..171471684371 --- /dev/null +++ b/ravenwood/runtime-common-device-src/com/android/ravenwood/common/divergence/RavenwoodDivergence.java @@ -0,0 +1,29 @@ +/* + * 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.ravenwood.common.divergence; + +/** + * A class that behaves differently on the device side and on Ravenwood, because we have + * two build modules with different implementation and we link the different ones at runtime. + */ +public final class RavenwoodDivergence { + private RavenwoodDivergence() { + } + + public static boolean isOnRavenwood() { + return false; + } +} diff --git a/ravenwood/runtime-common-ravenwood-src/com/android/ravenwood/common/divergence/RavenwoodDivergence.java b/ravenwood/runtime-common-ravenwood-src/com/android/ravenwood/common/divergence/RavenwoodDivergence.java new file mode 100644 index 000000000000..59f474a39033 --- /dev/null +++ b/ravenwood/runtime-common-ravenwood-src/com/android/ravenwood/common/divergence/RavenwoodDivergence.java @@ -0,0 +1,29 @@ +/* + * 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.ravenwood.common.divergence; + +/** + * A class that behaves differently on the device side and on Ravenwood, because we have + * two build modules with different implementation and we link the different ones at runtime. + */ +public final class RavenwoodDivergence { + private RavenwoodDivergence() { + } + + public static boolean isOnRavenwood() { + return true; + } +} diff --git a/ravenwood/runtime-common-src/com/android/ravenwood/common/JvmWorkaround.java b/ravenwood/runtime-common-src/com/android/ravenwood/common/JvmWorkaround.java new file mode 100644 index 000000000000..ee280991216a --- /dev/null +++ b/ravenwood/runtime-common-src/com/android/ravenwood/common/JvmWorkaround.java @@ -0,0 +1,68 @@ +/* + * 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.ravenwood.common; + +import java.io.FileDescriptor; + +/** + * Collection of methods to workaround limitation in the hostside JVM. + */ +public abstract class JvmWorkaround { + JvmWorkaround() { + } + + // We only support OpenJDK for now. + private static JvmWorkaround sInstance = + RavenwoodCommonUtils.isOnRavenwood() ? new OpenJdkWorkaround() : new NullWorkaround(); + + public static JvmWorkaround getInstance() { + return sInstance; + } + + /** + * Equivalent to Android's FileDescriptor.setInt$(). + */ + public abstract void setFdInt(FileDescriptor fd, int fdInt); + + + /** + * Equivalent to Android's FileDescriptor.getInt$(). + */ + public abstract int getFdInt(FileDescriptor fd); + + /** + * Placeholder implementation for the host side. + * + * Even on the host side, we don't want to throw just because the class is loaded, + * which could cause weird random issues, so we throw from individual methods rather + * than from the constructor. + */ + private static class NullWorkaround extends JvmWorkaround { + private RuntimeException calledOnHostside() { + throw new RuntimeException("This method shouldn't be called on the host side"); + } + + @Override + public void setFdInt(FileDescriptor fd, int fdInt) { + throw calledOnHostside(); + } + + @Override + public int getFdInt(FileDescriptor fd) { + throw calledOnHostside(); + } + } +} diff --git a/ravenwood/runtime-common-src/com/android/ravenwood/common/OpenJdkWorkaround.java b/ravenwood/runtime-common-src/com/android/ravenwood/common/OpenJdkWorkaround.java new file mode 100644 index 000000000000..9aedaab5b911 --- /dev/null +++ b/ravenwood/runtime-common-src/com/android/ravenwood/common/OpenJdkWorkaround.java @@ -0,0 +1,46 @@ +/* + * 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.ravenwood.common; + +import java.io.FileDescriptor; + +class OpenJdkWorkaround extends JvmWorkaround { + @Override + public void setFdInt(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); + } + } + + @Override + public int getFdInt(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); + } + } +} diff --git a/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodBadIntegrityException.java b/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodBadIntegrityException.java new file mode 100644 index 000000000000..61d54cba8b54 --- /dev/null +++ b/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodBadIntegrityException.java @@ -0,0 +1,26 @@ +/* + * 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.ravenwood.common; + +public class RavenwoodBadIntegrityException extends RavenwoodRuntimeException { + public RavenwoodBadIntegrityException(String message) { + super(message); + } + + public RavenwoodBadIntegrityException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodCommonUtils.java b/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodCommonUtils.java new file mode 100644 index 000000000000..c8cc8d9fe273 --- /dev/null +++ b/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodCommonUtils.java @@ -0,0 +1,234 @@ +/* + * 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.ravenwood.common; + +import com.android.ravenwood.common.divergence.RavenwoodDivergence; + +import java.io.File; +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.PrintStream; +import java.util.Arrays; + +public class RavenwoodCommonUtils { + private static final String TAG = "RavenwoodCommonUtils"; + + private RavenwoodCommonUtils() { + } + + private static final Object sLock = new Object(); + + /** Name of `libravenwood_runtime` */ + private static final String RAVENWOOD_NATIVE_RUNTIME_NAME = "ravenwood_runtime"; + + /** Directory name of `out/host/linux-x86/testcases/ravenwood-runtime` */ + private static final String RAVENWOOD_RUNTIME_DIR_NAME = "ravenwood-runtime"; + + private static boolean sEnableExtraRuntimeCheck = + "1".equals(System.getenv("RAVENWOOD_ENABLE_EXTRA_RUNTIME_CHECK")); + + private static final boolean IS_ON_RAVENWOOD = RavenwoodDivergence.isOnRavenwood(); + + private static final String RAVEWOOD_RUNTIME_PATH = getRavenwoodRuntimePathInternal(); + + public static final String RAVENWOOD_SYSPROP = "ro.is_on_ravenwood"; + + // @GuardedBy("sLock") + private static boolean sIntegrityChecked = false; + + /** + * @return if we're running on Ravenwood. + */ + public static boolean isOnRavenwood() { + return IS_ON_RAVENWOOD; + } + + /** + * Throws if the runtime is not Ravenwood. + */ + public static void ensureOnRavenwood() { + if (!isOnRavenwood()) { + throw new RavenwoodRuntimeException("This is only supposed to be used on Ravenwood"); + } + } + + /** + * @return if the various extra runtime check should be enabled. + */ + public static boolean shouldEnableExtraRuntimeCheck() { + return sEnableExtraRuntimeCheck; + } + + /** + * Load the main runtime JNI library. + */ + public static void loadRavenwoodNativeRuntime() { + ensureOnRavenwood(); + loadJniLibrary(RAVENWOOD_NATIVE_RUNTIME_NAME); + } + + /** + * Internal implementation of + * {@link android.platform.test.ravenwood.RavenwoodUtils#loadJniLibrary(String)} + */ + public static void loadJniLibrary(String libname) { + if (RavenwoodCommonUtils.isOnRavenwood()) { + loadJniLibraryInternal(libname); + } else { + System.loadLibrary(libname); + } + } + + /** + * Function equivalent to ART's System.loadLibrary. See RavenwoodUtils for why we need it. + */ + private static void loadJniLibraryInternal(String libname) { + var path = System.getProperty("java.library.path"); + var filename = "lib" + libname + ".so"; + + System.out.println("Looking for library " + libname + ".so in java.library.path:" + path); + + try { + if (path == null) { + throw new UnsatisfiedLinkError("Cannot load library " + libname + "." + + " Property java.library.path not set!"); + } + for (var dir : path.split(":")) { + var file = new File(dir + "/" + filename); + if (file.exists()) { + System.load(file.getAbsolutePath()); + return; + } + } + throw new UnsatisfiedLinkError("Library " + libname + " not found in " + + "java.library.path: " + path); + } catch (Throwable e) { + dumpFiles(System.out); + throw e; + } + } + + private static void dumpFiles(PrintStream out) { + try { + var path = System.getProperty("java.library.path"); + out.println("# java.library.path=" + path); + + for (var dir : path.split(":")) { + listFiles(out, new File(dir), ""); + + var gparent = new File((new File(dir)).getAbsolutePath() + "../../..") + .getCanonicalFile(); + if (gparent.getName().contains("testcases")) { + // Special case: if we found this directory, dump its contents too. + listFiles(out, gparent, ""); + } + } + + var gparent = new File("../..").getCanonicalFile(); + out.println("# ../..=" + gparent); + listFiles(out, gparent, ""); + } catch (Throwable th) { + out.println("Error: " + th.toString()); + th.printStackTrace(out); + } + } + + private static void listFiles(PrintStream out, File dir, String prefix) { + if (!dir.isDirectory()) { + out.println(prefix + dir.getAbsolutePath() + " is not a directory!"); + return; + } + out.println(prefix + ":" + dir.getAbsolutePath() + "/"); + // First, list the files. + for (var file : Arrays.stream(dir.listFiles()).sorted().toList()) { + out.println(prefix + " " + file.getName() + "" + (file.isDirectory() ? "/" : "")); + } + + // Then recurse. + if (dir.getAbsolutePath().startsWith("/usr") || dir.getAbsolutePath().startsWith("/lib")) { + // There would be too many files, so don't recurse. + return; + } + for (var file : Arrays.stream(dir.listFiles()).sorted().toList()) { + if (file.isDirectory()) { + listFiles(out, file, prefix + " "); + } + } + } + + /** + * @return the full directory path that contains the "ravenwood-runtime" files. + * + * This method throws if called on the device side. + */ + public static String getRavenwoodRuntimePath() { + ensureOnRavenwood(); + return RAVEWOOD_RUNTIME_PATH; + } + + private static String getRavenwoodRuntimePathInternal() { + if (!isOnRavenwood()) { + return null; + } + var path = System.getProperty("java.library.path"); + + System.out.println("Looking for " + RAVENWOOD_RUNTIME_DIR_NAME + " directory" + + " in java.library.path:" + path); + + try { + if (path == null) { + throw new IllegalStateException("java.library.path shouldn't be null"); + } + for (var dir : path.split(":")) { + + // For each path, see if the path contains RAVENWOOD_RUNTIME_DIR_NAME. + var d = new File(dir); + for (;;) { + if (d.getParent() == null) { + break; // Root dir, stop. + } + if (RAVENWOOD_RUNTIME_DIR_NAME.equals(d.getName())) { + var ret = d.getAbsolutePath() + "/"; + System.out.println("Found: " + ret); + return ret; + } + d = d.getParentFile(); + } + } + throw new IllegalStateException(RAVENWOOD_RUNTIME_DIR_NAME + " not found"); + } catch (Throwable e) { + dumpFiles(System.out); + throw e; + } + } + + /** Close an {@link AutoCloseable}. */ + public static void closeQuietly(AutoCloseable c) { + if (c != null) { + try { + c.close(); + } catch (Exception e) { + // Ignore + } + } + } + + /** Close a {@link FileDescriptor}. */ + public static void closeQuietly(FileDescriptor fd) { + var is = new FileInputStream(fd); + RavenwoodCommonUtils.closeQuietly(is); + } +} diff --git a/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodRuntimeException.java b/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodRuntimeException.java new file mode 100644 index 000000000000..7b0cebcecc1a --- /dev/null +++ b/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodRuntimeException.java @@ -0,0 +1,26 @@ +/* + * 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.ravenwood.common; + +public class RavenwoodRuntimeException extends RuntimeException { + public RavenwoodRuntimeException(String message) { + super(message); + } + + public RavenwoodRuntimeException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodRuntimeNative.java b/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodRuntimeNative.java new file mode 100644 index 000000000000..65402219ebee --- /dev/null +++ b/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodRuntimeNative.java @@ -0,0 +1,71 @@ +/* + * 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.ravenwood.common; + +import java.io.FileDescriptor; + +/** + * Class to host all the JNI methods used in ravenwood runtime. + */ +public class RavenwoodRuntimeNative { + private RavenwoodRuntimeNative() { + } + + static { + RavenwoodCommonUtils.ensureOnRavenwood(); + RavenwoodCommonUtils.loadRavenwoodNativeRuntime(); + } + + public static native void applyFreeFunction(long freeFunction, long nativePtr); + + public static native long nLseek(int fd, long offset, int whence); + + public static native int[] nPipe2(int flags); + + public static native int nDup(int oldfd); + + public static native int nFcntlInt(int fd, int cmd, int arg); + + public static long lseek(FileDescriptor fd, long offset, int whence) { + return nLseek(JvmWorkaround.getInstance().getFdInt(fd), offset, whence); + } + + public static FileDescriptor[] pipe2(int flags) { + var fds = nPipe2(flags); + var ret = new FileDescriptor[] { + new FileDescriptor(), + new FileDescriptor(), + }; + JvmWorkaround.getInstance().setFdInt(ret[0], fds[0]); + JvmWorkaround.getInstance().setFdInt(ret[1], fds[1]); + + return ret; + } + + public static FileDescriptor dup(FileDescriptor fd) { + var fdInt = nDup(JvmWorkaround.getInstance().getFdInt(fd)); + + var retFd = new java.io.FileDescriptor(); + JvmWorkaround.getInstance().setFdInt(retFd, fdInt); + return retFd; + } + + public static int fcntlInt(FileDescriptor fd, int cmd, int arg) { + var fdInt = JvmWorkaround.getInstance().getFdInt(fd); + + return nFcntlInt(fdInt, cmd, arg); + } +} diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/ParcelFileDescriptor_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/ParcelFileDescriptor_host.java index 2d799142df70..8fe6853abb45 100644 --- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/ParcelFileDescriptor_host.java +++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/ParcelFileDescriptor_host.java @@ -26,6 +26,7 @@ import static android.os.ParcelFileDescriptor.MODE_WORLD_WRITEABLE; import static android.os.ParcelFileDescriptor.MODE_WRITE_ONLY; import com.android.internal.annotations.GuardedBy; +import com.android.ravenwood.common.JvmWorkaround; import java.io.File; import java.io.FileDescriptor; @@ -46,27 +47,11 @@ public class ParcelFileDescriptor_host { 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); - } + JvmWorkaround.getInstance().setFdInt(fd, fdInt); } 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); - } + return JvmWorkaround.getInstance().getFdInt(fd); } public static FileDescriptor native_open$ravenwood(File file, int pfdMode) throws IOException { diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/RavenwoodEnvironment_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/RavenwoodEnvironment_host.java index 68bf92273022..b00cee02f611 100644 --- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/RavenwoodEnvironment_host.java +++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/RavenwoodEnvironment_host.java @@ -19,6 +19,7 @@ import android.platform.test.ravenwood.RavenwoodSystemProperties; import android.util.Log; import com.android.internal.ravenwood.RavenwoodEnvironment; +import com.android.ravenwood.common.RavenwoodCommonUtils; public class RavenwoodEnvironment_host { private static final String TAG = RavenwoodEnvironment.TAG; @@ -39,7 +40,7 @@ public class RavenwoodEnvironment_host { if (sInitialized) { return; } - Log.w(TAG, "Initializing Ravenwood environment"); + Log.i(TAG, "Initializing Ravenwood environment"); // Set the default values. var sysProps = RavenwoodSystemProperties.DEFAULT_VALUES; @@ -54,4 +55,4 @@ public class RavenwoodEnvironment_host { sInitialized = true; } } -} +}
\ No newline at end of file diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java index 69ff262fe915..e198646d4e27 100644 --- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java +++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java @@ -15,7 +15,7 @@ */ package com.android.platform.test.ravenwood.runtimehelper; -import android.platform.test.ravenwood.RavenwoodUtils; +import com.android.ravenwood.common.RavenwoodCommonUtils; import java.io.File; import java.lang.reflect.Modifier; @@ -141,7 +141,7 @@ public class ClassLoadHook { log("Loading " + LIBANDROID_RUNTIME_NAME + " for '" + libanrdoidClasses + "' and '" + libhwuiClasses + "'"); - RavenwoodUtils.loadJniLibrary(LIBANDROID_RUNTIME_NAME); + RavenwoodCommonUtils.loadJniLibrary(LIBANDROID_RUNTIME_NAME); } /** diff --git a/ravenwood/runtime-helper-src/jni/ravenwood_runtime.cpp b/ravenwood/runtime-helper-src/jni/ravenwood_runtime.cpp deleted file mode 100644 index 8e3a21dd6d87..000000000000 --- a/ravenwood/runtime-helper-src/jni/ravenwood_runtime.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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. - */ - -#include <nativehelper/JNIHelp.h> -#include "jni.h" -#include "utils/Log.h" -#include "utils/misc.h" - - -typedef void (*FreeFunction)(void*); - -static void NativeAllocationRegistry_applyFreeFunction(JNIEnv*, - jclass, - jlong freeFunction, - jlong ptr) { - void* nativePtr = reinterpret_cast<void*>(static_cast<uintptr_t>(ptr)); - FreeFunction nativeFreeFunction - = reinterpret_cast<FreeFunction>(static_cast<uintptr_t>(freeFunction)); - nativeFreeFunction(nativePtr); -} - -static const JNINativeMethod sMethods_NAR[] = -{ - { "applyFreeFunction", "(JJ)V", (void*)NativeAllocationRegistry_applyFreeFunction }, -}; - -extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) -{ - JNIEnv* env = NULL; - jint result = -1; - - if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { - ALOGE("GetEnv failed!"); - return result; - } - ALOG_ASSERT(env, "Could not retrieve the env!"); - - ALOGI("%s: JNI_OnLoad", __FILE__); - - // Initialize the Ravenwood version of NativeAllocationRegistry. - // We don't use this JNI on the device side, but if we ever have to do, skip this part. -#ifndef __ANDROID__ - int res = jniRegisterNativeMethods(env, "libcore/util/NativeAllocationRegistry", - sMethods_NAR, NELEM(sMethods_NAR)); - if (res < 0) { - return res; - } -#endif - - return JNI_VERSION_1_4; -} diff --git a/ravenwood/runtime-helper-src/libcore-fake/android/system/ErrnoException.java b/ravenwood/runtime-helper-src/libcore-fake/android/system/ErrnoException.java index 388156aa3694..843455d060c9 100644 --- a/ravenwood/runtime-helper-src/libcore-fake/android/system/ErrnoException.java +++ b/ravenwood/runtime-helper-src/libcore-fake/android/system/ErrnoException.java @@ -14,6 +14,8 @@ * limitations under the License. */ +// [ravenwood] Copied from libcore. + package android.system; import java.io.IOException; diff --git a/ravenwood/runtime-helper-src/libcore-fake/android/system/Os.java b/ravenwood/runtime-helper-src/libcore-fake/android/system/Os.java new file mode 100644 index 000000000000..e031eb27513b --- /dev/null +++ b/ravenwood/runtime-helper-src/libcore-fake/android/system/Os.java @@ -0,0 +1,45 @@ +/* + * 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 android.system; + +import com.android.ravenwood.common.RavenwoodRuntimeNative; + +import java.io.FileDescriptor; + +/** + * OS class replacement used on Ravenwood. For now, we just implement APIs as we need them... + * TODO(b/340887115): Need a better integration with libcore. + */ +public final class Os { + private Os() {} + + public static long lseek(FileDescriptor fd, long offset, int whence) throws ErrnoException { + return RavenwoodRuntimeNative.lseek(fd, offset, whence); + } + + + public static FileDescriptor[] pipe2(int flags) throws ErrnoException { + return RavenwoodRuntimeNative.pipe2(flags); + } + + public static FileDescriptor dup(FileDescriptor fd) throws ErrnoException { + return RavenwoodRuntimeNative.dup(fd); + } + + public static int fcntlInt(FileDescriptor fd, int cmd, int arg) throws ErrnoException { + return RavenwoodRuntimeNative.fcntlInt(fd, cmd, arg); + } +} diff --git a/ravenwood/runtime-helper-src/libcore-fake/android/system/OsConstants.java b/ravenwood/runtime-helper-src/libcore-fake/android/system/OsConstants.java new file mode 100644 index 000000000000..c56ec8a60f00 --- /dev/null +++ b/ravenwood/runtime-helper-src/libcore-fake/android/system/OsConstants.java @@ -0,0 +1,1259 @@ +/* + * Copyright (C) 2011 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 android.system; + +import com.android.ravenwood.common.RavenwoodCommonUtils; + +/** + * Copied from libcore's version, with the local changes: + * - All the imports are removed. (they're only used in javadoc) + * - All the annotations are removed. + * - The initConstants() method is moved to a nested class. + * + * TODO(b/340887115): Need a better integration with libcore. + */ + +public class OsConstants { +// @UnsupportedAppUsage + private OsConstants() { + } + + /** + * Returns the index of the element in the {@link StructCapUserData} (cap_user_data) + * array that this capability is stored in. + * + * @param x capability + * @return index of the element in the {@link StructCapUserData} array storing this capability + * + * @hide + */ +// @UnsupportedAppUsage +// @SystemApi(client = MODULE_LIBRARIES) + public static int CAP_TO_INDEX(int x) { return x >>> 5; } + + /** + * Returns the mask for the given capability. This is relative to the capability's + * {@link StructCapUserData} (cap_user_data) element, the index of which can be + * retrieved with {@link CAP_TO_INDEX}. + * + * @param x capability + * @return mask for given capability + * + * @hide + */ +// @UnsupportedAppUsage +// @SystemApi(client = MODULE_LIBRARIES) + public static int CAP_TO_MASK(int x) { return 1 << (x & 31); } + + /** + * Tests whether the given mode is a block device. + */ + public static boolean S_ISBLK(int mode) { return (mode & S_IFMT) == S_IFBLK; } + + /** + * Tests whether the given mode is a character device. + */ + public static boolean S_ISCHR(int mode) { return (mode & S_IFMT) == S_IFCHR; } + + /** + * Tests whether the given mode is a directory. + */ + public static boolean S_ISDIR(int mode) { return (mode & S_IFMT) == S_IFDIR; } + + /** + * Tests whether the given mode is a FIFO. + */ + public static boolean S_ISFIFO(int mode) { return (mode & S_IFMT) == S_IFIFO; } + + /** + * Tests whether the given mode is a regular file. + */ + public static boolean S_ISREG(int mode) { return (mode & S_IFMT) == S_IFREG; } + + /** + * Tests whether the given mode is a symbolic link. + */ + public static boolean S_ISLNK(int mode) { return (mode & S_IFMT) == S_IFLNK; } + + /** + * Tests whether the given mode is a socket. + */ + public static boolean S_ISSOCK(int mode) { return (mode & S_IFMT) == S_IFSOCK; } + + /** + * Extracts the exit status of a child. Only valid if WIFEXITED returns true. + */ + public static int WEXITSTATUS(int status) { return (status & 0xff00) >> 8; } + + /** + * Tests whether the child dumped core. Only valid if WIFSIGNALED returns true. + */ + public static boolean WCOREDUMP(int status) { return (status & 0x80) != 0; } + + /** + * Returns the signal that caused the child to exit. Only valid if WIFSIGNALED returns true. + */ + public static int WTERMSIG(int status) { return status & 0x7f; } + + /** + * Returns the signal that cause the child to stop. Only valid if WIFSTOPPED returns true. + */ + public static int WSTOPSIG(int status) { return WEXITSTATUS(status); } + + /** + * Tests whether the child exited normally. + */ + public static boolean WIFEXITED(int status) { return (WTERMSIG(status) == 0); } + + /** + * Tests whether the child was stopped (not terminated) by a signal. + */ + public static boolean WIFSTOPPED(int status) { return (WTERMSIG(status) == 0x7f); } + + /** + * Tests whether the child was terminated by a signal. + */ + public static boolean WIFSIGNALED(int status) { return (WTERMSIG(status + 1) >= 2); } + + public static final int AF_INET = placeholder(); + public static final int AF_INET6 = placeholder(); + public static final int AF_NETLINK = placeholder(); + public static final int AF_PACKET = placeholder(); + public static final int AF_UNIX = placeholder(); + + /** + * The virt-vsock address family, linux specific. + * It is used with {@code struct sockaddr_vm} from uapi/linux/vm_sockets.h. + * + * @see <a href="https://man7.org/linux/man-pages/man7/vsock.7.html">vsock(7)</a> + * @see VmSocketAddress + */ + public static final int AF_VSOCK = placeholder(); + public static final int AF_UNSPEC = placeholder(); + public static final int AI_ADDRCONFIG = placeholder(); + public static final int AI_ALL = placeholder(); + public static final int AI_CANONNAME = placeholder(); + public static final int AI_NUMERICHOST = placeholder(); + public static final int AI_NUMERICSERV = placeholder(); + public static final int AI_PASSIVE = placeholder(); + public static final int AI_V4MAPPED = placeholder(); + public static final int ARPHRD_ETHER = placeholder(); + + /** + * The virtio-vsock {@code svmPort} value to bind for any available port. + * + * @see <a href="https://man7.org/linux/man-pages/man7/vsock.7.html">vsock(7)</a> + * @see VmSocketAddress + */ + public static final int VMADDR_PORT_ANY = placeholder(); + + /** + * The virtio-vsock {@code svmCid} value to listens for all CIDs. + * + * @see <a href="https://man7.org/linux/man-pages/man7/vsock.7.html">vsock(7)</a> + * @see VmSocketAddress + */ + public static final int VMADDR_CID_ANY = placeholder(); + + /** + * The virtio-vsock {@code svmCid} value for host communication. + * + * @see <a href="https://man7.org/linux/man-pages/man7/vsock.7.html">vsock(7)</a> + * @see VmSocketAddress + */ + public static final int VMADDR_CID_LOCAL = placeholder(); + + /** + * The virtio-vsock {@code svmCid} value for loopback communication. + * + * @see <a href="https://man7.org/linux/man-pages/man7/vsock.7.html">vsock(7)</a> + * @see VmSocketAddress + */ + public static final int VMADDR_CID_HOST = placeholder(); + + /** + * ARP protocol loopback device identifier. + * + * @hide + */ +// @UnsupportedAppUsage +// @SystemApi(client = MODULE_LIBRARIES) + public static final int ARPHRD_LOOPBACK = placeholder(); + public static final int CAP_AUDIT_CONTROL = placeholder(); + public static final int CAP_AUDIT_WRITE = placeholder(); + public static final int CAP_BLOCK_SUSPEND = placeholder(); + public static final int CAP_CHOWN = placeholder(); + public static final int CAP_DAC_OVERRIDE = placeholder(); + public static final int CAP_DAC_READ_SEARCH = placeholder(); + public static final int CAP_FOWNER = placeholder(); + public static final int CAP_FSETID = placeholder(); + public static final int CAP_IPC_LOCK = placeholder(); + public static final int CAP_IPC_OWNER = placeholder(); + public static final int CAP_KILL = placeholder(); + public static final int CAP_LAST_CAP = placeholder(); + public static final int CAP_LEASE = placeholder(); + public static final int CAP_LINUX_IMMUTABLE = placeholder(); + public static final int CAP_MAC_ADMIN = placeholder(); + public static final int CAP_MAC_OVERRIDE = placeholder(); + public static final int CAP_MKNOD = placeholder(); + public static final int CAP_NET_ADMIN = placeholder(); + public static final int CAP_NET_BIND_SERVICE = placeholder(); + public static final int CAP_NET_BROADCAST = placeholder(); + public static final int CAP_NET_RAW = placeholder(); + public static final int CAP_SETFCAP = placeholder(); + public static final int CAP_SETGID = placeholder(); + public static final int CAP_SETPCAP = placeholder(); + public static final int CAP_SETUID = placeholder(); + public static final int CAP_SYS_ADMIN = placeholder(); + public static final int CAP_SYS_BOOT = placeholder(); + public static final int CAP_SYS_CHROOT = placeholder(); + public static final int CAP_SYSLOG = placeholder(); + public static final int CAP_SYS_MODULE = placeholder(); + public static final int CAP_SYS_NICE = placeholder(); + public static final int CAP_SYS_PACCT = placeholder(); + public static final int CAP_SYS_PTRACE = placeholder(); + public static final int CAP_SYS_RAWIO = placeholder(); + public static final int CAP_SYS_RESOURCE = placeholder(); + public static final int CAP_SYS_TIME = placeholder(); + public static final int CAP_SYS_TTY_CONFIG = placeholder(); + public static final int CAP_WAKE_ALARM = placeholder(); + public static final int E2BIG = placeholder(); + public static final int EACCES = placeholder(); + public static final int EADDRINUSE = placeholder(); + public static final int EADDRNOTAVAIL = placeholder(); + public static final int EAFNOSUPPORT = placeholder(); + public static final int EAGAIN = placeholder(); + public static final int EAI_AGAIN = placeholder(); + public static final int EAI_BADFLAGS = placeholder(); + public static final int EAI_FAIL = placeholder(); + public static final int EAI_FAMILY = placeholder(); + public static final int EAI_MEMORY = placeholder(); + public static final int EAI_NODATA = placeholder(); + public static final int EAI_NONAME = placeholder(); + public static final int EAI_OVERFLOW = placeholder(); + public static final int EAI_SERVICE = placeholder(); + public static final int EAI_SOCKTYPE = placeholder(); + public static final int EAI_SYSTEM = placeholder(); + public static final int EALREADY = placeholder(); + public static final int EBADF = placeholder(); + public static final int EBADMSG = placeholder(); + public static final int EBUSY = placeholder(); + public static final int ECANCELED = placeholder(); + public static final int ECHILD = placeholder(); + public static final int ECONNABORTED = placeholder(); + public static final int ECONNREFUSED = placeholder(); + public static final int ECONNRESET = placeholder(); + public static final int EDEADLK = placeholder(); + public static final int EDESTADDRREQ = placeholder(); + public static final int EDOM = placeholder(); + public static final int EDQUOT = placeholder(); + public static final int EEXIST = placeholder(); + public static final int EFAULT = placeholder(); + public static final int EFBIG = placeholder(); + public static final int EHOSTUNREACH = placeholder(); + public static final int EIDRM = placeholder(); + public static final int EILSEQ = placeholder(); + public static final int EINPROGRESS = placeholder(); + public static final int EINTR = placeholder(); + public static final int EINVAL = placeholder(); + public static final int EIO = placeholder(); + public static final int EISCONN = placeholder(); + public static final int EISDIR = placeholder(); + public static final int ELOOP = placeholder(); + public static final int EMFILE = placeholder(); + public static final int EMLINK = placeholder(); + public static final int EMSGSIZE = placeholder(); + public static final int EMULTIHOP = placeholder(); + public static final int ENAMETOOLONG = placeholder(); + public static final int ENETDOWN = placeholder(); + public static final int ENETRESET = placeholder(); + public static final int ENETUNREACH = placeholder(); + public static final int ENFILE = placeholder(); + public static final int ENOBUFS = placeholder(); + public static final int ENODATA = placeholder(); + public static final int ENODEV = placeholder(); + public static final int ENOENT = placeholder(); + public static final int ENOEXEC = placeholder(); + public static final int ENOLCK = placeholder(); + public static final int ENOLINK = placeholder(); + public static final int ENOMEM = placeholder(); + public static final int ENOMSG = placeholder(); + public static final int ENONET = placeholder(); + public static final int ENOPROTOOPT = placeholder(); + public static final int ENOSPC = placeholder(); + public static final int ENOSR = placeholder(); + public static final int ENOSTR = placeholder(); + public static final int ENOSYS = placeholder(); + public static final int ENOTCONN = placeholder(); + public static final int ENOTDIR = placeholder(); + public static final int ENOTEMPTY = placeholder(); + public static final int ENOTSOCK = placeholder(); + public static final int ENOTSUP = placeholder(); + public static final int ENOTTY = placeholder(); + public static final int ENXIO = placeholder(); + public static final int EOPNOTSUPP = placeholder(); + public static final int EOVERFLOW = placeholder(); + public static final int EPERM = placeholder(); + public static final int EPIPE = placeholder(); + public static final int EPROTO = placeholder(); + public static final int EPROTONOSUPPORT = placeholder(); + public static final int EPROTOTYPE = placeholder(); + public static final int ERANGE = placeholder(); + public static final int EROFS = placeholder(); + public static final int ESPIPE = placeholder(); + public static final int ESRCH = placeholder(); + public static final int ESTALE = placeholder(); + public static final int ETH_P_ALL = placeholder(); + public static final int ETH_P_ARP = placeholder(); + public static final int ETH_P_IP = placeholder(); + public static final int ETH_P_IPV6 = placeholder(); + public static final int ETIME = placeholder(); + public static final int ETIMEDOUT = placeholder(); + public static final int ETXTBSY = placeholder(); + /** + * "Too many users" error. + * See <a href="https://man7.org/linux/man-pages/man3/errno.3.html">errno(3)</a>. + * + * @hide + */ +// @UnsupportedAppUsage +// @SystemApi(client = MODULE_LIBRARIES) + public static final int EUSERS = placeholder(); + // On Linux, EWOULDBLOCK == EAGAIN. Use EAGAIN instead, to reduce confusion. + public static final int EXDEV = placeholder(); + public static final int EXIT_FAILURE = placeholder(); + public static final int EXIT_SUCCESS = placeholder(); + public static final int FD_CLOEXEC = placeholder(); + public static final int FIONREAD = placeholder(); + public static final int F_DUPFD = placeholder(); + public static final int F_DUPFD_CLOEXEC = placeholder(); + public static final int F_GETFD = placeholder(); + public static final int F_GETFL = placeholder(); + public static final int F_GETLK = placeholder(); + public static final int F_GETLK64 = placeholder(); + public static final int F_GETOWN = placeholder(); + public static final int F_OK = placeholder(); + public static final int F_RDLCK = placeholder(); + public static final int F_SETFD = placeholder(); + public static final int F_SETFL = placeholder(); + public static final int F_SETLK = placeholder(); + public static final int F_SETLK64 = placeholder(); + public static final int F_SETLKW = placeholder(); + public static final int F_SETLKW64 = placeholder(); + public static final int F_SETOWN = placeholder(); + public static final int F_UNLCK = placeholder(); + public static final int F_WRLCK = placeholder(); + public static final int ICMP_ECHO = placeholder(); + public static final int ICMP_ECHOREPLY = placeholder(); + public static final int ICMP6_ECHO_REQUEST = placeholder(); + public static final int ICMP6_ECHO_REPLY = placeholder(); + public static final int IFA_F_DADFAILED = placeholder(); + public static final int IFA_F_DEPRECATED = placeholder(); + public static final int IFA_F_HOMEADDRESS = placeholder(); + public static final int IFA_F_MANAGETEMPADDR = placeholder(); + public static final int IFA_F_NODAD = placeholder(); + public static final int IFA_F_NOPREFIXROUTE = placeholder(); + public static final int IFA_F_OPTIMISTIC = placeholder(); + public static final int IFA_F_PERMANENT = placeholder(); + public static final int IFA_F_SECONDARY = placeholder(); + public static final int IFA_F_TEMPORARY = placeholder(); + public static final int IFA_F_TENTATIVE = placeholder(); + public static final int IFF_ALLMULTI = placeholder(); + public static final int IFF_AUTOMEDIA = placeholder(); + public static final int IFF_BROADCAST = placeholder(); + public static final int IFF_DEBUG = placeholder(); + public static final int IFF_DYNAMIC = placeholder(); + public static final int IFF_LOOPBACK = placeholder(); + public static final int IFF_MASTER = placeholder(); + public static final int IFF_MULTICAST = placeholder(); + public static final int IFF_NOARP = placeholder(); + public static final int IFF_NOTRAILERS = placeholder(); + public static final int IFF_POINTOPOINT = placeholder(); + public static final int IFF_PORTSEL = placeholder(); + public static final int IFF_PROMISC = placeholder(); + public static final int IFF_RUNNING = placeholder(); + public static final int IFF_SLAVE = placeholder(); + public static final int IFF_UP = placeholder(); + public static final int IPPROTO_ICMP = placeholder(); + public static final int IPPROTO_ICMPV6 = placeholder(); + public static final int IPPROTO_IP = placeholder(); + public static final int IPPROTO_IPV6 = placeholder(); + public static final int IPPROTO_RAW = placeholder(); + public static final int IPPROTO_TCP = placeholder(); + public static final int IPPROTO_UDP = placeholder(); + + /** + * Encapsulation Security Payload protocol + * + * <p>Defined in /uapi/linux/in.h + */ + public static final int IPPROTO_ESP = placeholder(); + + public static final int IPV6_CHECKSUM = placeholder(); + public static final int IPV6_MULTICAST_HOPS = placeholder(); + public static final int IPV6_MULTICAST_IF = placeholder(); + public static final int IPV6_MULTICAST_LOOP = placeholder(); + public static final int IPV6_PKTINFO = placeholder(); + public static final int IPV6_RECVDSTOPTS = placeholder(); + public static final int IPV6_RECVHOPLIMIT = placeholder(); + public static final int IPV6_RECVHOPOPTS = placeholder(); + public static final int IPV6_RECVPKTINFO = placeholder(); + public static final int IPV6_RECVRTHDR = placeholder(); + public static final int IPV6_RECVTCLASS = placeholder(); + public static final int IPV6_TCLASS = placeholder(); + public static final int IPV6_UNICAST_HOPS = placeholder(); + public static final int IPV6_V6ONLY = placeholder(); + /** @hide */ +// @UnsupportedAppUsage + public static final int IP_MULTICAST_ALL = placeholder(); + public static final int IP_MULTICAST_IF = placeholder(); + public static final int IP_MULTICAST_LOOP = placeholder(); + public static final int IP_MULTICAST_TTL = placeholder(); + /** @hide */ +// @UnsupportedAppUsage + public static final int IP_RECVTOS = placeholder(); + public static final int IP_TOS = placeholder(); + public static final int IP_TTL = placeholder(); + /** + * Version constant to be used in {@link StructCapUserHeader} with + * {@link Os#capset(StructCapUserHeader, StructCapUserData[])} and + * {@link Os#capget(StructCapUserHeader)}. + * + * See <a href="https://man7.org/linux/man-pages/man2/capget.2.html">capget(2)</a>. + * + * @hide + */ +// @UnsupportedAppUsage +// @SystemApi(client = MODULE_LIBRARIES) + public static final int _LINUX_CAPABILITY_VERSION_3 = placeholder(); + public static final int MAP_FIXED = placeholder(); + public static final int MAP_ANONYMOUS = placeholder(); + /** + * Flag argument for {@code mmap(long, long, int, int, FileDescriptor, long)}. + * + * See <a href="http://man7.org/linux/man-pages/man2/mmap.2.html">mmap(2)</a>. + * + * @hide + */ +// @UnsupportedAppUsage +// @SystemApi(client = MODULE_LIBRARIES) + public static final int MAP_POPULATE = placeholder(); + public static final int MAP_PRIVATE = placeholder(); + public static final int MAP_SHARED = placeholder(); + public static final int MCAST_JOIN_GROUP = placeholder(); + public static final int MCAST_LEAVE_GROUP = placeholder(); + public static final int MCAST_JOIN_SOURCE_GROUP = placeholder(); + public static final int MCAST_LEAVE_SOURCE_GROUP = placeholder(); + public static final int MCAST_BLOCK_SOURCE = placeholder(); + public static final int MCAST_UNBLOCK_SOURCE = placeholder(); + public static final int MCL_CURRENT = placeholder(); + public static final int MCL_FUTURE = placeholder(); + public static final int MFD_CLOEXEC = placeholder(); + public static final int MSG_CTRUNC = placeholder(); + public static final int MSG_DONTROUTE = placeholder(); + public static final int MSG_EOR = placeholder(); + public static final int MSG_OOB = placeholder(); + public static final int MSG_PEEK = placeholder(); + public static final int MSG_TRUNC = placeholder(); + public static final int MSG_WAITALL = placeholder(); + public static final int MS_ASYNC = placeholder(); + public static final int MS_INVALIDATE = placeholder(); + public static final int MS_SYNC = placeholder(); + public static final int NETLINK_NETFILTER = placeholder(); + public static final int NETLINK_ROUTE = placeholder(); + /** + * SELinux enforces that only system_server and netd may use this netlink socket type. + */ + public static final int NETLINK_INET_DIAG = placeholder(); + + /** + * SELinux enforces that only system_server and netd may use this netlink socket type. + * + * @see <a href="https://man7.org/linux/man-pages/man7/netlink.7.html">netlink(7)</a> + */ + public static final int NETLINK_XFRM = placeholder(); + + public static final int NI_DGRAM = placeholder(); + public static final int NI_NAMEREQD = placeholder(); + public static final int NI_NOFQDN = placeholder(); + public static final int NI_NUMERICHOST = placeholder(); + public static final int NI_NUMERICSERV = placeholder(); + public static final int O_ACCMODE = placeholder(); + public static final int O_APPEND = placeholder(); + public static final int O_CLOEXEC = placeholder(); + public static final int O_CREAT = placeholder(); + /** + * Flag for {@code Os#open(String, int, int)}. + * + * When enabled, tries to minimize cache effects of the I/O to and from this + * file. In general this will degrade performance, but it is + * useful in special situations, such as when applications do + * their own caching. File I/O is done directly to/from + * user-space buffers. The {@link O_DIRECT} flag on its own makes an + * effort to transfer data synchronously, but does not give + * the guarantees of the {@link O_SYNC} flag that data and necessary + * metadata are transferred. To guarantee synchronous I/O, + * {@link O_SYNC} must be used in addition to {@link O_DIRECT}. + * + * See <a href="https://man7.org/linux/man-pages/man2/open.2.html">open(2)</a>. + * + * @hide + */ +// @UnsupportedAppUsage +// @SystemApi(client = MODULE_LIBRARIES) + public static final int O_DIRECT = placeholder(); + public static final int O_EXCL = placeholder(); + public static final int O_NOCTTY = placeholder(); + public static final int O_NOFOLLOW = placeholder(); + public static final int O_NONBLOCK = placeholder(); + public static final int O_RDONLY = placeholder(); + public static final int O_RDWR = placeholder(); + public static final int O_SYNC = placeholder(); + public static final int O_DSYNC = placeholder(); + public static final int O_TRUNC = placeholder(); + public static final int O_WRONLY = placeholder(); + public static final int POLLERR = placeholder(); + public static final int POLLHUP = placeholder(); + public static final int POLLIN = placeholder(); + public static final int POLLNVAL = placeholder(); + public static final int POLLOUT = placeholder(); + public static final int POLLPRI = placeholder(); + public static final int POLLRDBAND = placeholder(); + public static final int POLLRDNORM = placeholder(); + public static final int POLLWRBAND = placeholder(); + public static final int POLLWRNORM = placeholder(); + /** + * Reads or changes the ambient capability set of the calling thread. + * Has to be used as a first argument for {@link Os#prctl(int, long, long, long, long)}. + * + * See <a href="https://man7.org/linux/man-pages/man2/prctl.2.html">prctl(2)</a>. + * + * @hide + */ +// @UnsupportedAppUsage +// @SystemApi(client = MODULE_LIBRARIES) + public static final int PR_CAP_AMBIENT = placeholder(); + /** + * The capability specified in {@code arg3} of {@link Os#prctl(int, long, long, long, long)} + * is added to the ambient set. The specified capability must already + * be present in both the permitted and the inheritable sets of the process. + * Has to be used as a second argument for {@link Os#prctl(int, long, long, long, long)}. + * + * See <a href="https://man7.org/linux/man-pages/man2/prctl.2.html">prctl(2)</a>. + * @hide + */ +// @UnsupportedAppUsage +// @SystemApi(client = MODULE_LIBRARIES) + public static final int PR_CAP_AMBIENT_RAISE = placeholder(); + public static final int PR_GET_DUMPABLE = placeholder(); + public static final int PR_SET_DUMPABLE = placeholder(); + public static final int PR_SET_NO_NEW_PRIVS = placeholder(); + public static final int PROT_EXEC = placeholder(); + public static final int PROT_NONE = placeholder(); + public static final int PROT_READ = placeholder(); + public static final int PROT_WRITE = placeholder(); + public static final int R_OK = placeholder(); + /** + * Specifies a value one greater than the maximum file + * descriptor number that can be opened by this process. + * + * <p>Attempts ({@link Os#open(String, int, int)}, {@link Os#pipe()}, + * {@link Os#dup(java.io.FileDescriptor)}, etc.) to exceed this + * limit yield the error {@link EMFILE}. + * + * See <a href="https://man7.org/linux/man-pages/man3/vlimit.3.html">getrlimit(2)</a>. + * + * @hide + */ +// @UnsupportedAppUsage +// @SystemApi(client = MODULE_LIBRARIES) + public static final int RLIMIT_NOFILE = placeholder(); + public static final int RT_SCOPE_HOST = placeholder(); + public static final int RT_SCOPE_LINK = placeholder(); + public static final int RT_SCOPE_NOWHERE = placeholder(); + public static final int RT_SCOPE_SITE = placeholder(); + public static final int RT_SCOPE_UNIVERSE = placeholder(); + /** + * Bitmask for IPv4 addresses add/delete events multicast groups mask. + * Used in {@link NetlinkSocketAddress}. + * + * See <a href="https://man7.org/linux/man-pages/man7/netlink.7.html">netlink(7)</a>. + * + * @hide + */ +// @UnsupportedAppUsage +// @SystemApi(client = MODULE_LIBRARIES) + public static final int RTMGRP_IPV4_IFADDR = placeholder(); + /** @hide */ +// @UnsupportedAppUsage + public static final int RTMGRP_IPV4_MROUTE = placeholder(); + /** @hide */ +// @UnsupportedAppUsage + public static final int RTMGRP_IPV4_ROUTE = placeholder(); + /** @hide */ +// @UnsupportedAppUsage + public static final int RTMGRP_IPV4_RULE = placeholder(); + /** @hide */ +// @UnsupportedAppUsage + public static final int RTMGRP_IPV6_IFADDR = placeholder(); + /** @hide */ +// @UnsupportedAppUsage + public static final int RTMGRP_IPV6_IFINFO = placeholder(); + /** @hide */ +// @UnsupportedAppUsage + public static final int RTMGRP_IPV6_MROUTE = placeholder(); + /** @hide */ +// @UnsupportedAppUsage + public static final int RTMGRP_IPV6_PREFIX = placeholder(); + /** @hide */ +// @UnsupportedAppUsage + public static final int RTMGRP_IPV6_ROUTE = placeholder(); + /** @hide */ +// @UnsupportedAppUsage + public static final int RTMGRP_LINK = placeholder(); + public static final int RTMGRP_NEIGH = placeholder(); + /** @hide */ +// @UnsupportedAppUsage + public static final int RTMGRP_NOTIFY = placeholder(); + /** @hide */ +// @UnsupportedAppUsage + public static final int RTMGRP_TC = placeholder(); + public static final int SEEK_CUR = placeholder(); + public static final int SEEK_END = placeholder(); + public static final int SEEK_SET = placeholder(); + public static final int SHUT_RD = placeholder(); + public static final int SHUT_RDWR = placeholder(); + public static final int SHUT_WR = placeholder(); + public static final int SIGABRT = placeholder(); + public static final int SIGALRM = placeholder(); + public static final int SIGBUS = placeholder(); + public static final int SIGCHLD = placeholder(); + public static final int SIGCONT = placeholder(); + public static final int SIGFPE = placeholder(); + public static final int SIGHUP = placeholder(); + public static final int SIGILL = placeholder(); + public static final int SIGINT = placeholder(); + public static final int SIGIO = placeholder(); + public static final int SIGKILL = placeholder(); + public static final int SIGPIPE = placeholder(); + public static final int SIGPROF = placeholder(); + public static final int SIGPWR = placeholder(); + public static final int SIGQUIT = placeholder(); + public static final int SIGRTMAX = placeholder(); + public static final int SIGRTMIN = placeholder(); + public static final int SIGSEGV = placeholder(); + public static final int SIGSTKFLT = placeholder(); + public static final int SIGSTOP = placeholder(); + public static final int SIGSYS = placeholder(); + public static final int SIGTERM = placeholder(); + public static final int SIGTRAP = placeholder(); + public static final int SIGTSTP = placeholder(); + public static final int SIGTTIN = placeholder(); + public static final int SIGTTOU = placeholder(); + public static final int SIGURG = placeholder(); + public static final int SIGUSR1 = placeholder(); + public static final int SIGUSR2 = placeholder(); + public static final int SIGVTALRM = placeholder(); + public static final int SIGWINCH = placeholder(); + public static final int SIGXCPU = placeholder(); + public static final int SIGXFSZ = placeholder(); + public static final int SIOCGIFADDR = placeholder(); + public static final int SIOCGIFBRDADDR = placeholder(); + public static final int SIOCGIFDSTADDR = placeholder(); + public static final int SIOCGIFNETMASK = placeholder(); + + /** + * Set the close-on-exec ({@code FD_CLOEXEC}) flag on the new file + * descriptor created by {@link Os#socket(int,int,int)} or + * {@link Os#socketpair(int,int,int,java.io.FileDescriptor,java.io.FileDescriptor)}. + * See the description of the O_CLOEXEC flag in + * <a href="http://man7.org/linux/man-pages/man2/open.2.html">open(2)</a> + * for reasons why this may be useful. + * + * <p>Applications wishing to make use of this flag on older API versions + * may use {@link #O_CLOEXEC} instead. On Android, {@code O_CLOEXEC} and + * {@code SOCK_CLOEXEC} are the same value. + */ + public static final int SOCK_CLOEXEC = placeholder(); + public static final int SOCK_DGRAM = placeholder(); + + /** + * Set the O_NONBLOCK file status flag on the file descriptor + * created by {@link Os#socket(int,int,int)} or + * {@link Os#socketpair(int,int,int,java.io.FileDescriptor,java.io.FileDescriptor)}. + * + * <p>Applications wishing to make use of this flag on older API versions + * may use {@link #O_NONBLOCK} instead. On Android, {@code O_NONBLOCK} + * and {@code SOCK_NONBLOCK} are the same value. + */ + public static final int SOCK_NONBLOCK = placeholder(); + public static final int SOCK_RAW = placeholder(); + public static final int SOCK_SEQPACKET = placeholder(); + public static final int SOCK_STREAM = placeholder(); + public static final int SOL_SOCKET = placeholder(); + public static final int SOL_UDP = placeholder(); + public static final int SOL_PACKET = placeholder(); + public static final int SO_BINDTODEVICE = placeholder(); + public static final int SO_BROADCAST = placeholder(); + public static final int SO_DEBUG = placeholder(); + /** @hide */ +// @UnsupportedAppUsage + public static final int SO_DOMAIN = placeholder(); + public static final int SO_DONTROUTE = placeholder(); + public static final int SO_ERROR = placeholder(); + public static final int SO_KEEPALIVE = placeholder(); + public static final int SO_LINGER = placeholder(); + public static final int SO_OOBINLINE = placeholder(); + public static final int SO_PASSCRED = placeholder(); + public static final int SO_PEERCRED = placeholder(); + /** @hide */ +// @UnsupportedAppUsage + public static final int SO_PROTOCOL = placeholder(); + public static final int SO_RCVBUF = placeholder(); + public static final int SO_RCVLOWAT = placeholder(); + public static final int SO_RCVTIMEO = placeholder(); + public static final int SO_REUSEADDR = placeholder(); + public static final int SO_SNDBUF = placeholder(); + public static final int SO_SNDLOWAT = placeholder(); + public static final int SO_SNDTIMEO = placeholder(); + public static final int SO_TYPE = placeholder(); + public static final int PACKET_IGNORE_OUTGOING = placeholder(); + /** + * Bitmask for flags argument of + * {@link splice(java.io.FileDescriptor, Int64Ref , FileDescriptor, Int64Ref, long, int)}. + * + * Attempt to move pages instead of copying. This is only a + * hint to the kernel: pages may still be copied if the + * kernel cannot move the pages from the pipe, or if the pipe + * buffers don't refer to full pages. + * + * See <a href="https://man7.org/linux/man-pages/man2/splice.2.html">splice(2)</a>. + * + * @hide + */ +// @UnsupportedAppUsage +// @SystemApi(client = MODULE_LIBRARIES) + public static final int SPLICE_F_MOVE = placeholder(); + /** @hide */ +// @UnsupportedAppUsage + public static final int SPLICE_F_NONBLOCK = placeholder(); + /** + * Bitmask for flags argument of + * {@link splice(java.io.FileDescriptor, Int64Ref, FileDescriptor, Int64Ref, long, int)}. + * + * <p>Indicates that more data will be coming in a subsequent splice. This is + * a helpful hint when the {@code fdOut} refers to a socket. + * + * See <a href="https://man7.org/linux/man-pages/man2/splice.2.html">splice(2)</a>. + * + * @hide + */ +// @UnsupportedAppUsage +// @SystemApi(client = MODULE_LIBRARIES) + public static final int SPLICE_F_MORE = placeholder(); + public static final int STDERR_FILENO = placeholder(); + public static final int STDIN_FILENO = placeholder(); + public static final int STDOUT_FILENO = placeholder(); + public static final int ST_MANDLOCK = placeholder(); + public static final int ST_NOATIME = placeholder(); + public static final int ST_NODEV = placeholder(); + public static final int ST_NODIRATIME = placeholder(); + public static final int ST_NOEXEC = placeholder(); + public static final int ST_NOSUID = placeholder(); + public static final int ST_RDONLY = placeholder(); + public static final int ST_RELATIME = placeholder(); + public static final int ST_SYNCHRONOUS = placeholder(); + public static final int S_IFBLK = placeholder(); + public static final int S_IFCHR = placeholder(); + public static final int S_IFDIR = placeholder(); + public static final int S_IFIFO = placeholder(); + public static final int S_IFLNK = placeholder(); + public static final int S_IFMT = placeholder(); + public static final int S_IFREG = placeholder(); + public static final int S_IFSOCK = placeholder(); + public static final int S_IRGRP = placeholder(); + public static final int S_IROTH = placeholder(); + public static final int S_IRUSR = placeholder(); + public static final int S_IRWXG = placeholder(); + public static final int S_IRWXO = placeholder(); + public static final int S_IRWXU = placeholder(); + public static final int S_ISGID = placeholder(); + public static final int S_ISUID = placeholder(); + public static final int S_ISVTX = placeholder(); + public static final int S_IWGRP = placeholder(); + public static final int S_IWOTH = placeholder(); + public static final int S_IWUSR = placeholder(); + public static final int S_IXGRP = placeholder(); + public static final int S_IXOTH = placeholder(); + public static final int S_IXUSR = placeholder(); + public static final int TCP_NODELAY = placeholder(); + public static final int TCP_USER_TIMEOUT = placeholder(); + public static final int UDP_GRO = placeholder(); + public static final int UDP_SEGMENT = placeholder(); + /** + * Get the number of bytes in the output buffer. + * + * See <a href="https://man7.org/linux/man-pages/man2/ioctl.2.html">ioctl(2)</a>. + * + * @hide + */ +// @UnsupportedAppUsage +// @SystemApi(client = MODULE_LIBRARIES) + public static final int TIOCOUTQ = placeholder(); + /** + * Sockopt option to encapsulate ESP packets in UDP. + * + * @hide + */ +// @UnsupportedAppUsage +// @SystemApi(client = MODULE_LIBRARIES) + public static final int UDP_ENCAP = placeholder(); + /** @hide */ +// @UnsupportedAppUsage + public static final int UDP_ENCAP_ESPINUDP_NON_IKE = placeholder(); + /** @hide */ +// @UnsupportedAppUsage +// @SystemApi(client = MODULE_LIBRARIES) + public static final int UDP_ENCAP_ESPINUDP = placeholder(); + /** @hide */ +// @UnsupportedAppUsage + public static final int UNIX_PATH_MAX = placeholder(); + public static final int WCONTINUED = placeholder(); + public static final int WEXITED = placeholder(); + public static final int WNOHANG = placeholder(); + public static final int WNOWAIT = placeholder(); + public static final int WSTOPPED = placeholder(); + public static final int WUNTRACED = placeholder(); + public static final int W_OK = placeholder(); + /** + * {@code flags} option for {@link Os#setxattr(String, String, byte[], int)}. + * + * <p>Performs a pure create, which fails if the named attribute exists already. + * + * See <a href="http://man7.org/linux/man-pages/man2/setxattr.2.html">setxattr(2)</a>. + * + * @hide + */ +// @UnsupportedAppUsage +// @SystemApi(client = MODULE_LIBRARIES) + public static final int XATTR_CREATE = placeholder(); + /** + * {@code flags} option for {@link Os#setxattr(String, String, byte[], int)}. + * + * <p>Perform a pure replace operation, which fails if the named attribute + * does not already exist. + * + * See <a href="http://man7.org/linux/man-pages/man2/setxattr.2.html">setxattr(2)</a>. + * + * @hide + */ +// @UnsupportedAppUsage +// @SystemApi(client = MODULE_LIBRARIES) + public static final int XATTR_REPLACE = placeholder(); + public static final int X_OK = placeholder(); + public static final int _SC_2_CHAR_TERM = placeholder(); + public static final int _SC_2_C_BIND = placeholder(); + public static final int _SC_2_C_DEV = placeholder(); + public static final int _SC_2_C_VERSION = placeholder(); + public static final int _SC_2_FORT_DEV = placeholder(); + public static final int _SC_2_FORT_RUN = placeholder(); + public static final int _SC_2_LOCALEDEF = placeholder(); + public static final int _SC_2_SW_DEV = placeholder(); + public static final int _SC_2_UPE = placeholder(); + public static final int _SC_2_VERSION = placeholder(); + public static final int _SC_AIO_LISTIO_MAX = placeholder(); + public static final int _SC_AIO_MAX = placeholder(); + public static final int _SC_AIO_PRIO_DELTA_MAX = placeholder(); + public static final int _SC_ARG_MAX = placeholder(); + public static final int _SC_ASYNCHRONOUS_IO = placeholder(); + public static final int _SC_ATEXIT_MAX = placeholder(); + public static final int _SC_AVPHYS_PAGES = placeholder(); + public static final int _SC_BC_BASE_MAX = placeholder(); + public static final int _SC_BC_DIM_MAX = placeholder(); + public static final int _SC_BC_SCALE_MAX = placeholder(); + public static final int _SC_BC_STRING_MAX = placeholder(); + public static final int _SC_CHILD_MAX = placeholder(); + public static final int _SC_CLK_TCK = placeholder(); + public static final int _SC_COLL_WEIGHTS_MAX = placeholder(); + public static final int _SC_DELAYTIMER_MAX = placeholder(); + public static final int _SC_EXPR_NEST_MAX = placeholder(); + public static final int _SC_FSYNC = placeholder(); + public static final int _SC_GETGR_R_SIZE_MAX = placeholder(); + public static final int _SC_GETPW_R_SIZE_MAX = placeholder(); + public static final int _SC_IOV_MAX = placeholder(); + public static final int _SC_JOB_CONTROL = placeholder(); + public static final int _SC_LINE_MAX = placeholder(); + public static final int _SC_LOGIN_NAME_MAX = placeholder(); + public static final int _SC_MAPPED_FILES = placeholder(); + public static final int _SC_MEMLOCK = placeholder(); + public static final int _SC_MEMLOCK_RANGE = placeholder(); + public static final int _SC_MEMORY_PROTECTION = placeholder(); + public static final int _SC_MESSAGE_PASSING = placeholder(); + public static final int _SC_MQ_OPEN_MAX = placeholder(); + public static final int _SC_MQ_PRIO_MAX = placeholder(); + public static final int _SC_NGROUPS_MAX = placeholder(); + public static final int _SC_NPROCESSORS_CONF = placeholder(); + public static final int _SC_NPROCESSORS_ONLN = placeholder(); + public static final int _SC_OPEN_MAX = placeholder(); + public static final int _SC_PAGESIZE = placeholder(); + public static final int _SC_PAGE_SIZE = placeholder(); + public static final int _SC_PASS_MAX = placeholder(); + public static final int _SC_PHYS_PAGES = placeholder(); + public static final int _SC_PRIORITIZED_IO = placeholder(); + public static final int _SC_PRIORITY_SCHEDULING = placeholder(); + public static final int _SC_REALTIME_SIGNALS = placeholder(); + public static final int _SC_RE_DUP_MAX = placeholder(); + public static final int _SC_RTSIG_MAX = placeholder(); + public static final int _SC_SAVED_IDS = placeholder(); + public static final int _SC_SEMAPHORES = placeholder(); + public static final int _SC_SEM_NSEMS_MAX = placeholder(); + public static final int _SC_SEM_VALUE_MAX = placeholder(); + public static final int _SC_SHARED_MEMORY_OBJECTS = placeholder(); + public static final int _SC_SIGQUEUE_MAX = placeholder(); + public static final int _SC_STREAM_MAX = placeholder(); + public static final int _SC_SYNCHRONIZED_IO = placeholder(); + public static final int _SC_THREADS = placeholder(); + public static final int _SC_THREAD_ATTR_STACKADDR = placeholder(); + public static final int _SC_THREAD_ATTR_STACKSIZE = placeholder(); + public static final int _SC_THREAD_DESTRUCTOR_ITERATIONS = placeholder(); + public static final int _SC_THREAD_KEYS_MAX = placeholder(); + public static final int _SC_THREAD_PRIORITY_SCHEDULING = placeholder(); + public static final int _SC_THREAD_PRIO_INHERIT = placeholder(); + public static final int _SC_THREAD_PRIO_PROTECT = placeholder(); + public static final int _SC_THREAD_SAFE_FUNCTIONS = placeholder(); + public static final int _SC_THREAD_STACK_MIN = placeholder(); + public static final int _SC_THREAD_THREADS_MAX = placeholder(); + public static final int _SC_TIMERS = placeholder(); + public static final int _SC_TIMER_MAX = placeholder(); + public static final int _SC_TTY_NAME_MAX = placeholder(); + public static final int _SC_TZNAME_MAX = placeholder(); + public static final int _SC_VERSION = placeholder(); + public static final int _SC_XBS5_ILP32_OFF32 = placeholder(); + public static final int _SC_XBS5_ILP32_OFFBIG = placeholder(); + public static final int _SC_XBS5_LP64_OFF64 = placeholder(); + public static final int _SC_XBS5_LPBIG_OFFBIG = placeholder(); + public static final int _SC_XOPEN_CRYPT = placeholder(); + public static final int _SC_XOPEN_ENH_I18N = placeholder(); + public static final int _SC_XOPEN_LEGACY = placeholder(); + public static final int _SC_XOPEN_REALTIME = placeholder(); + public static final int _SC_XOPEN_REALTIME_THREADS = placeholder(); + public static final int _SC_XOPEN_SHM = placeholder(); + public static final int _SC_XOPEN_UNIX = placeholder(); + public static final int _SC_XOPEN_VERSION = placeholder(); + public static final int _SC_XOPEN_XCU_VERSION = placeholder(); + + /** + * Returns the string name of a getaddrinfo(3) error value. + * For example, "EAI_AGAIN". + */ + public static String gaiName(int error) { + if (error == EAI_AGAIN) { + return "EAI_AGAIN"; + } + if (error == EAI_BADFLAGS) { + return "EAI_BADFLAGS"; + } + if (error == EAI_FAIL) { + return "EAI_FAIL"; + } + if (error == EAI_FAMILY) { + return "EAI_FAMILY"; + } + if (error == EAI_MEMORY) { + return "EAI_MEMORY"; + } + if (error == EAI_NODATA) { + return "EAI_NODATA"; + } + if (error == EAI_NONAME) { + return "EAI_NONAME"; + } + if (error == EAI_OVERFLOW) { + return "EAI_OVERFLOW"; + } + if (error == EAI_SERVICE) { + return "EAI_SERVICE"; + } + if (error == EAI_SOCKTYPE) { + return "EAI_SOCKTYPE"; + } + if (error == EAI_SYSTEM) { + return "EAI_SYSTEM"; + } + return null; + } + + /** + * Returns the string name of an errno value. + * For example, "EACCES". See {@link Os#strerror} for human-readable errno descriptions. + */ + public static String errnoName(int errno) { + if (errno == E2BIG) { + return "E2BIG"; + } + if (errno == EACCES) { + return "EACCES"; + } + if (errno == EADDRINUSE) { + return "EADDRINUSE"; + } + if (errno == EADDRNOTAVAIL) { + return "EADDRNOTAVAIL"; + } + if (errno == EAFNOSUPPORT) { + return "EAFNOSUPPORT"; + } + if (errno == EAGAIN) { + return "EAGAIN"; + } + if (errno == EALREADY) { + return "EALREADY"; + } + if (errno == EBADF) { + return "EBADF"; + } + if (errno == EBADMSG) { + return "EBADMSG"; + } + if (errno == EBUSY) { + return "EBUSY"; + } + if (errno == ECANCELED) { + return "ECANCELED"; + } + if (errno == ECHILD) { + return "ECHILD"; + } + if (errno == ECONNABORTED) { + return "ECONNABORTED"; + } + if (errno == ECONNREFUSED) { + return "ECONNREFUSED"; + } + if (errno == ECONNRESET) { + return "ECONNRESET"; + } + if (errno == EDEADLK) { + return "EDEADLK"; + } + if (errno == EDESTADDRREQ) { + return "EDESTADDRREQ"; + } + if (errno == EDOM) { + return "EDOM"; + } + if (errno == EDQUOT) { + return "EDQUOT"; + } + if (errno == EEXIST) { + return "EEXIST"; + } + if (errno == EFAULT) { + return "EFAULT"; + } + if (errno == EFBIG) { + return "EFBIG"; + } + if (errno == EHOSTUNREACH) { + return "EHOSTUNREACH"; + } + if (errno == EIDRM) { + return "EIDRM"; + } + if (errno == EILSEQ) { + return "EILSEQ"; + } + if (errno == EINPROGRESS) { + return "EINPROGRESS"; + } + if (errno == EINTR) { + return "EINTR"; + } + if (errno == EINVAL) { + return "EINVAL"; + } + if (errno == EIO) { + return "EIO"; + } + if (errno == EISCONN) { + return "EISCONN"; + } + if (errno == EISDIR) { + return "EISDIR"; + } + if (errno == ELOOP) { + return "ELOOP"; + } + if (errno == EMFILE) { + return "EMFILE"; + } + if (errno == EMLINK) { + return "EMLINK"; + } + if (errno == EMSGSIZE) { + return "EMSGSIZE"; + } + if (errno == EMULTIHOP) { + return "EMULTIHOP"; + } + if (errno == ENAMETOOLONG) { + return "ENAMETOOLONG"; + } + if (errno == ENETDOWN) { + return "ENETDOWN"; + } + if (errno == ENETRESET) { + return "ENETRESET"; + } + if (errno == ENETUNREACH) { + return "ENETUNREACH"; + } + if (errno == ENFILE) { + return "ENFILE"; + } + if (errno == ENOBUFS) { + return "ENOBUFS"; + } + if (errno == ENODATA) { + return "ENODATA"; + } + if (errno == ENODEV) { + return "ENODEV"; + } + if (errno == ENOENT) { + return "ENOENT"; + } + if (errno == ENOEXEC) { + return "ENOEXEC"; + } + if (errno == ENOLCK) { + return "ENOLCK"; + } + if (errno == ENOLINK) { + return "ENOLINK"; + } + if (errno == ENOMEM) { + return "ENOMEM"; + } + if (errno == ENOMSG) { + return "ENOMSG"; + } + if (errno == ENONET) { + return "ENONET"; + } + if (errno == ENOPROTOOPT) { + return "ENOPROTOOPT"; + } + if (errno == ENOSPC) { + return "ENOSPC"; + } + if (errno == ENOSR) { + return "ENOSR"; + } + if (errno == ENOSTR) { + return "ENOSTR"; + } + if (errno == ENOSYS) { + return "ENOSYS"; + } + if (errno == ENOTCONN) { + return "ENOTCONN"; + } + if (errno == ENOTDIR) { + return "ENOTDIR"; + } + if (errno == ENOTEMPTY) { + return "ENOTEMPTY"; + } + if (errno == ENOTSOCK) { + return "ENOTSOCK"; + } + if (errno == ENOTSUP) { + return "ENOTSUP"; + } + if (errno == ENOTTY) { + return "ENOTTY"; + } + if (errno == ENXIO) { + return "ENXIO"; + } + if (errno == EOPNOTSUPP) { + return "EOPNOTSUPP"; + } + if (errno == EOVERFLOW) { + return "EOVERFLOW"; + } + if (errno == EPERM) { + return "EPERM"; + } + if (errno == EPIPE) { + return "EPIPE"; + } + if (errno == EPROTO) { + return "EPROTO"; + } + if (errno == EPROTONOSUPPORT) { + return "EPROTONOSUPPORT"; + } + if (errno == EPROTOTYPE) { + return "EPROTOTYPE"; + } + if (errno == ERANGE) { + return "ERANGE"; + } + if (errno == EROFS) { + return "EROFS"; + } + if (errno == ESPIPE) { + return "ESPIPE"; + } + if (errno == ESRCH) { + return "ESRCH"; + } + if (errno == ESTALE) { + return "ESTALE"; + } + if (errno == ETIME) { + return "ETIME"; + } + if (errno == ETIMEDOUT) { + return "ETIMEDOUT"; + } + if (errno == ETXTBSY) { + return "ETXTBSY"; + } + if (errno == EXDEV) { + return "EXDEV"; + } + return null; + } + + // [ravenwood-change] Moved to a nested class. + // @UnsupportedAppUsage + static class Native { + private static native void initConstants(); + } + + // A hack to avoid these constants being inlined by javac... +// @UnsupportedAppUsage + private static int placeholder() { return 0; } + // ...because we want to initialize them at runtime. + static { + // [ravenwood-change] Load the JNI lib. + RavenwoodCommonUtils.loadRavenwoodNativeRuntime(); + Native.initConstants(); + } +} diff --git a/ravenwood/runtime-helper-src/libcore-fake/libcore/ravenwood/LibcoreRavenwoodUtils.java b/ravenwood/runtime-helper-src/libcore-fake/libcore/ravenwood/LibcoreRavenwoodUtils.java deleted file mode 100644 index 839b62a39471..000000000000 --- a/ravenwood/runtime-helper-src/libcore-fake/libcore/ravenwood/LibcoreRavenwoodUtils.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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 libcore.ravenwood; - -public class LibcoreRavenwoodUtils { - private LibcoreRavenwoodUtils() { - } - - public static void loadRavenwoodNativeRuntime() { - // TODO Stop using reflections. - // We need to call RavenwoodUtils.loadRavenwoodNativeRuntime(), but due to the build - // structure complexity, we can't refer to to this method directly from here, - // so let's use reflections for now... - try { - final var clazz = Class.forName("android.platform.test.ravenwood.RavenwoodUtils"); - final var method = clazz.getMethod("loadRavenwoodNativeRuntime"); - method.invoke(null); - } catch (Throwable th) { - throw new IllegalStateException("Failed to load Ravenwood native runtime", th); - } - } -} diff --git a/ravenwood/runtime-helper-src/libcore-fake/libcore/util/NativeAllocationRegistry.java b/ravenwood/runtime-helper-src/libcore-fake/libcore/util/NativeAllocationRegistry.java index 93861e87318f..14b5a4f0c1e0 100644 --- a/ravenwood/runtime-helper-src/libcore-fake/libcore/util/NativeAllocationRegistry.java +++ b/ravenwood/runtime-helper-src/libcore-fake/libcore/util/NativeAllocationRegistry.java @@ -15,7 +15,7 @@ */ package libcore.util; -import libcore.ravenwood.LibcoreRavenwoodUtils; +import com.android.ravenwood.common.RavenwoodRuntimeNative; import java.lang.ref.Cleaner; import java.lang.ref.Reference; @@ -27,11 +27,6 @@ import java.lang.ref.Reference; * (Should ART switch to java.lang.ref.Cleaner?) */ public class NativeAllocationRegistry { - static { - // Initialize the JNI method. - LibcoreRavenwoodUtils.loadRavenwoodNativeRuntime(); - } - private final long mFreeFunction; private static final Cleaner sCleaner = Cleaner.create(); @@ -71,7 +66,7 @@ public class NativeAllocationRegistry { } final Runnable releaser = () -> { - applyFreeFunction(mFreeFunction, nativePtr); + RavenwoodRuntimeNative.applyFreeFunction(mFreeFunction, nativePtr); }; sCleaner.register(referent, releaser); @@ -79,10 +74,4 @@ public class NativeAllocationRegistry { Reference.reachabilityFence(referent); return releaser; } - - /** - * Calls {@code freeFunction}({@code nativePtr}). - */ - public static native void applyFreeFunction(long freeFunction, long nativePtr); } - diff --git a/ravenwood/runtime-jni/ravenwood_os_constants.cpp b/ravenwood/runtime-jni/ravenwood_os_constants.cpp new file mode 100644 index 000000000000..ea6c9d4766b6 --- /dev/null +++ b/ravenwood/runtime-jni/ravenwood_os_constants.cpp @@ -0,0 +1,766 @@ +/* + * 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. + */ + +// Copied from libcore/luni/src/main/native/android_system_OsConstants.cpp, +// changes annotated with [ravenwood-change]. + +#define LOG_TAG "OsConstants" + +#include <errno.h> +#include <fcntl.h> +#include <netdb.h> +#include <netinet/icmp6.h> +#include <netinet/in.h> +#include <netinet/ip_icmp.h> +#include <netinet/tcp.h> +#include <poll.h> +#include <signal.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/prctl.h> +#include <sys/resource.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/un.h> +#include <sys/wait.h> +#include <sys/xattr.h> +#include <unistd.h> + +#include <net/if_arp.h> +#include <linux/if_ether.h> + +// After the others because these are not necessarily self-contained in glibc. +#include <linux/if_addr.h> +#include <linux/rtnetlink.h> + +// Include linux socket constants for setting sockopts +#include <linux/udp.h> + +#include <net/if.h> // After <sys/socket.h> to work around a Mac header file bug. + +// [ravenwood-change] always include it +// #if defined(__BIONIC__) +#include <linux/capability.h> +// #endif + +#include <nativehelper/JNIHelp.h> +#include <nativehelper/jni_macros.h> + +// [ravenwood-change] -- can't access "Portability.h", so just inline it here. +// #include "Portability.h" +#include <byteswap.h> +#include <sys/sendfile.h> +#include <sys/statvfs.h> +#include <netdb.h> +#include <linux/vm_sockets.h> + +// For LOG_ALWAYS_FATAL_IF +#include "utils/Log.h" + + +static void initConstant(JNIEnv* env, jclass c, const char* fieldName, int value) { + jfieldID field = env->GetStaticFieldID(c, fieldName, "I"); + env->SetStaticIntField(c, field, value); +} + +static void OsConstants_initConstants(JNIEnv* env, jclass) { + // [ravenwood-change] -- the constants are in the outer class, but this JNI method is in the + // nested class, so we need to get the outer class here. + jclass c = env->FindClass("android/system/OsConstants"); + LOG_ALWAYS_FATAL_IF(c == NULL, "Unable to find class android/system/OsConstants"); + + initConstant(env, c, "AF_INET", AF_INET); + initConstant(env, c, "AF_INET6", AF_INET6); + initConstant(env, c, "AF_PACKET", AF_PACKET); + initConstant(env, c, "AF_NETLINK", AF_NETLINK); + initConstant(env, c, "AF_UNIX", AF_UNIX); + initConstant(env, c, "AF_VSOCK", AF_VSOCK); + initConstant(env, c, "AF_UNSPEC", AF_UNSPEC); + initConstant(env, c, "AI_ADDRCONFIG", AI_ADDRCONFIG); + initConstant(env, c, "AI_ALL", AI_ALL); + initConstant(env, c, "AI_CANONNAME", AI_CANONNAME); + initConstant(env, c, "AI_NUMERICHOST", AI_NUMERICHOST); +#if defined(AI_NUMERICSERV) + initConstant(env, c, "AI_NUMERICSERV", AI_NUMERICSERV); +#endif + initConstant(env, c, "AI_PASSIVE", AI_PASSIVE); + initConstant(env, c, "AI_V4MAPPED", AI_V4MAPPED); + initConstant(env, c, "ARPHRD_ETHER", ARPHRD_ETHER); + initConstant(env, c, "VMADDR_PORT_ANY", VMADDR_PORT_ANY); + initConstant(env, c, "VMADDR_CID_ANY", VMADDR_CID_ANY); + initConstant(env, c, "VMADDR_CID_LOCAL", VMADDR_CID_LOCAL); + initConstant(env, c, "VMADDR_CID_HOST", VMADDR_CID_HOST); + initConstant(env, c, "ARPHRD_LOOPBACK", ARPHRD_LOOPBACK); +#if defined(CAP_LAST_CAP) + initConstant(env, c, "CAP_AUDIT_CONTROL", CAP_AUDIT_CONTROL); + initConstant(env, c, "CAP_AUDIT_WRITE", CAP_AUDIT_WRITE); + initConstant(env, c, "CAP_BLOCK_SUSPEND", CAP_BLOCK_SUSPEND); + initConstant(env, c, "CAP_CHOWN", CAP_CHOWN); + initConstant(env, c, "CAP_DAC_OVERRIDE", CAP_DAC_OVERRIDE); + initConstant(env, c, "CAP_DAC_READ_SEARCH", CAP_DAC_READ_SEARCH); + initConstant(env, c, "CAP_FOWNER", CAP_FOWNER); + initConstant(env, c, "CAP_FSETID", CAP_FSETID); + initConstant(env, c, "CAP_IPC_LOCK", CAP_IPC_LOCK); + initConstant(env, c, "CAP_IPC_OWNER", CAP_IPC_OWNER); + initConstant(env, c, "CAP_KILL", CAP_KILL); + initConstant(env, c, "CAP_LAST_CAP", CAP_LAST_CAP); + initConstant(env, c, "CAP_LEASE", CAP_LEASE); + initConstant(env, c, "CAP_LINUX_IMMUTABLE", CAP_LINUX_IMMUTABLE); + initConstant(env, c, "CAP_MAC_ADMIN", CAP_MAC_ADMIN); + initConstant(env, c, "CAP_MAC_OVERRIDE", CAP_MAC_OVERRIDE); + initConstant(env, c, "CAP_MKNOD", CAP_MKNOD); + initConstant(env, c, "CAP_NET_ADMIN", CAP_NET_ADMIN); + initConstant(env, c, "CAP_NET_BIND_SERVICE", CAP_NET_BIND_SERVICE); + initConstant(env, c, "CAP_NET_BROADCAST", CAP_NET_BROADCAST); + initConstant(env, c, "CAP_NET_RAW", CAP_NET_RAW); + initConstant(env, c, "CAP_SETFCAP", CAP_SETFCAP); + initConstant(env, c, "CAP_SETGID", CAP_SETGID); + initConstant(env, c, "CAP_SETPCAP", CAP_SETPCAP); + initConstant(env, c, "CAP_SETUID", CAP_SETUID); + initConstant(env, c, "CAP_SYS_ADMIN", CAP_SYS_ADMIN); + initConstant(env, c, "CAP_SYS_BOOT", CAP_SYS_BOOT); + initConstant(env, c, "CAP_SYS_CHROOT", CAP_SYS_CHROOT); + initConstant(env, c, "CAP_SYSLOG", CAP_SYSLOG); + initConstant(env, c, "CAP_SYS_MODULE", CAP_SYS_MODULE); + initConstant(env, c, "CAP_SYS_NICE", CAP_SYS_NICE); + initConstant(env, c, "CAP_SYS_PACCT", CAP_SYS_PACCT); + initConstant(env, c, "CAP_SYS_PTRACE", CAP_SYS_PTRACE); + initConstant(env, c, "CAP_SYS_RAWIO", CAP_SYS_RAWIO); + initConstant(env, c, "CAP_SYS_RESOURCE", CAP_SYS_RESOURCE); + initConstant(env, c, "CAP_SYS_TIME", CAP_SYS_TIME); + initConstant(env, c, "CAP_SYS_TTY_CONFIG", CAP_SYS_TTY_CONFIG); + initConstant(env, c, "CAP_WAKE_ALARM", CAP_WAKE_ALARM); +#endif + initConstant(env, c, "E2BIG", E2BIG); + initConstant(env, c, "EACCES", EACCES); + initConstant(env, c, "EADDRINUSE", EADDRINUSE); + initConstant(env, c, "EADDRNOTAVAIL", EADDRNOTAVAIL); + initConstant(env, c, "EAFNOSUPPORT", EAFNOSUPPORT); + initConstant(env, c, "EAGAIN", EAGAIN); + initConstant(env, c, "EAI_AGAIN", EAI_AGAIN); + initConstant(env, c, "EAI_BADFLAGS", EAI_BADFLAGS); + initConstant(env, c, "EAI_FAIL", EAI_FAIL); + initConstant(env, c, "EAI_FAMILY", EAI_FAMILY); + initConstant(env, c, "EAI_MEMORY", EAI_MEMORY); + initConstant(env, c, "EAI_NODATA", EAI_NODATA); + initConstant(env, c, "EAI_NONAME", EAI_NONAME); +#if defined(EAI_OVERFLOW) + initConstant(env, c, "EAI_OVERFLOW", EAI_OVERFLOW); +#endif + initConstant(env, c, "EAI_SERVICE", EAI_SERVICE); + initConstant(env, c, "EAI_SOCKTYPE", EAI_SOCKTYPE); + initConstant(env, c, "EAI_SYSTEM", EAI_SYSTEM); + initConstant(env, c, "EALREADY", EALREADY); + initConstant(env, c, "EBADF", EBADF); + initConstant(env, c, "EBADMSG", EBADMSG); + initConstant(env, c, "EBUSY", EBUSY); + initConstant(env, c, "ECANCELED", ECANCELED); + initConstant(env, c, "ECHILD", ECHILD); + initConstant(env, c, "ECONNABORTED", ECONNABORTED); + initConstant(env, c, "ECONNREFUSED", ECONNREFUSED); + initConstant(env, c, "ECONNRESET", ECONNRESET); + initConstant(env, c, "EDEADLK", EDEADLK); + initConstant(env, c, "EDESTADDRREQ", EDESTADDRREQ); + initConstant(env, c, "EDOM", EDOM); + initConstant(env, c, "EDQUOT", EDQUOT); + initConstant(env, c, "EEXIST", EEXIST); + initConstant(env, c, "EFAULT", EFAULT); + initConstant(env, c, "EFBIG", EFBIG); + initConstant(env, c, "EHOSTUNREACH", EHOSTUNREACH); + initConstant(env, c, "EIDRM", EIDRM); + initConstant(env, c, "EILSEQ", EILSEQ); + initConstant(env, c, "EINPROGRESS", EINPROGRESS); + initConstant(env, c, "EINTR", EINTR); + initConstant(env, c, "EINVAL", EINVAL); + initConstant(env, c, "EIO", EIO); + initConstant(env, c, "EISCONN", EISCONN); + initConstant(env, c, "EISDIR", EISDIR); + initConstant(env, c, "ELOOP", ELOOP); + initConstant(env, c, "EMFILE", EMFILE); + initConstant(env, c, "EMLINK", EMLINK); + initConstant(env, c, "EMSGSIZE", EMSGSIZE); + initConstant(env, c, "EMULTIHOP", EMULTIHOP); + initConstant(env, c, "ENAMETOOLONG", ENAMETOOLONG); + initConstant(env, c, "ENETDOWN", ENETDOWN); + initConstant(env, c, "ENETRESET", ENETRESET); + initConstant(env, c, "ENETUNREACH", ENETUNREACH); + initConstant(env, c, "ENFILE", ENFILE); + initConstant(env, c, "ENOBUFS", ENOBUFS); + initConstant(env, c, "ENODATA", ENODATA); + initConstant(env, c, "ENODEV", ENODEV); + initConstant(env, c, "ENOENT", ENOENT); + initConstant(env, c, "ENOEXEC", ENOEXEC); + initConstant(env, c, "ENOLCK", ENOLCK); + initConstant(env, c, "ENOLINK", ENOLINK); + initConstant(env, c, "ENOMEM", ENOMEM); + initConstant(env, c, "ENOMSG", ENOMSG); + initConstant(env, c, "ENONET", ENONET); + initConstant(env, c, "ENOPROTOOPT", ENOPROTOOPT); + initConstant(env, c, "ENOSPC", ENOSPC); + initConstant(env, c, "ENOSR", ENOSR); + initConstant(env, c, "ENOSTR", ENOSTR); + initConstant(env, c, "ENOSYS", ENOSYS); + initConstant(env, c, "ENOTCONN", ENOTCONN); + initConstant(env, c, "ENOTDIR", ENOTDIR); + initConstant(env, c, "ENOTEMPTY", ENOTEMPTY); + initConstant(env, c, "ENOTSOCK", ENOTSOCK); + initConstant(env, c, "ENOTSUP", ENOTSUP); + initConstant(env, c, "ENOTTY", ENOTTY); + initConstant(env, c, "ENXIO", ENXIO); + initConstant(env, c, "EOPNOTSUPP", EOPNOTSUPP); + initConstant(env, c, "EOVERFLOW", EOVERFLOW); + initConstant(env, c, "EPERM", EPERM); + initConstant(env, c, "EPIPE", EPIPE); + initConstant(env, c, "EPROTO", EPROTO); + initConstant(env, c, "EPROTONOSUPPORT", EPROTONOSUPPORT); + initConstant(env, c, "EPROTOTYPE", EPROTOTYPE); + initConstant(env, c, "ERANGE", ERANGE); + initConstant(env, c, "EROFS", EROFS); + initConstant(env, c, "ESPIPE", ESPIPE); + initConstant(env, c, "ESRCH", ESRCH); + initConstant(env, c, "ESTALE", ESTALE); + initConstant(env, c, "ETH_P_ALL", ETH_P_ALL); + initConstant(env, c, "ETH_P_ARP", ETH_P_ARP); + initConstant(env, c, "ETH_P_IP", ETH_P_IP); + initConstant(env, c, "ETH_P_IPV6", ETH_P_IPV6); + initConstant(env, c, "ETIME", ETIME); + initConstant(env, c, "ETIMEDOUT", ETIMEDOUT); + initConstant(env, c, "ETXTBSY", ETXTBSY); + initConstant(env, c, "EUSERS", EUSERS); +#if EWOULDBLOCK != EAGAIN +#error EWOULDBLOCK != EAGAIN +#endif + initConstant(env, c, "EXDEV", EXDEV); + initConstant(env, c, "EXIT_FAILURE", EXIT_FAILURE); + initConstant(env, c, "EXIT_SUCCESS", EXIT_SUCCESS); + initConstant(env, c, "FD_CLOEXEC", FD_CLOEXEC); + initConstant(env, c, "FIONREAD", FIONREAD); + initConstant(env, c, "F_DUPFD", F_DUPFD); + initConstant(env, c, "F_DUPFD_CLOEXEC", F_DUPFD_CLOEXEC); + initConstant(env, c, "F_GETFD", F_GETFD); + initConstant(env, c, "F_GETFL", F_GETFL); + initConstant(env, c, "F_GETLK", F_GETLK); +#if defined(F_GETLK64) + initConstant(env, c, "F_GETLK64", F_GETLK64); +#endif + initConstant(env, c, "F_GETOWN", F_GETOWN); + initConstant(env, c, "F_OK", F_OK); + initConstant(env, c, "F_RDLCK", F_RDLCK); + initConstant(env, c, "F_SETFD", F_SETFD); + initConstant(env, c, "F_SETFL", F_SETFL); + initConstant(env, c, "F_SETLK", F_SETLK); +#if defined(F_SETLK64) + initConstant(env, c, "F_SETLK64", F_SETLK64); +#endif + initConstant(env, c, "F_SETLKW", F_SETLKW); +#if defined(F_SETLKW64) + initConstant(env, c, "F_SETLKW64", F_SETLKW64); +#endif + initConstant(env, c, "F_SETOWN", F_SETOWN); + initConstant(env, c, "F_UNLCK", F_UNLCK); + initConstant(env, c, "F_WRLCK", F_WRLCK); + initConstant(env, c, "ICMP_ECHO", ICMP_ECHO); + initConstant(env, c, "ICMP_ECHOREPLY", ICMP_ECHOREPLY); + initConstant(env, c, "ICMP6_ECHO_REQUEST", ICMP6_ECHO_REQUEST); + initConstant(env, c, "ICMP6_ECHO_REPLY", ICMP6_ECHO_REPLY); +#if defined(IFA_F_DADFAILED) + initConstant(env, c, "IFA_F_DADFAILED", IFA_F_DADFAILED); +#endif +#if defined(IFA_F_DEPRECATED) + initConstant(env, c, "IFA_F_DEPRECATED", IFA_F_DEPRECATED); +#endif +#if defined(IFA_F_HOMEADDRESS) + initConstant(env, c, "IFA_F_HOMEADDRESS", IFA_F_HOMEADDRESS); +#endif +#if defined(IFA_F_MANAGETEMPADDR) + initConstant(env, c, "IFA_F_MANAGETEMPADDR", IFA_F_MANAGETEMPADDR); +#endif +#if defined(IFA_F_NODAD) + initConstant(env, c, "IFA_F_NODAD", IFA_F_NODAD); +#endif +#if defined(IFA_F_NOPREFIXROUTE) + initConstant(env, c, "IFA_F_NOPREFIXROUTE", IFA_F_NOPREFIXROUTE); +#endif +#if defined(IFA_F_OPTIMISTIC) + initConstant(env, c, "IFA_F_OPTIMISTIC", IFA_F_OPTIMISTIC); +#endif +#if defined(IFA_F_PERMANENT) + initConstant(env, c, "IFA_F_PERMANENT", IFA_F_PERMANENT); +#endif +#if defined(IFA_F_SECONDARY) + initConstant(env, c, "IFA_F_SECONDARY", IFA_F_SECONDARY); +#endif +#if defined(IFA_F_TEMPORARY) + initConstant(env, c, "IFA_F_TEMPORARY", IFA_F_TEMPORARY); +#endif +#if defined(IFA_F_TENTATIVE) + initConstant(env, c, "IFA_F_TENTATIVE", IFA_F_TENTATIVE); +#endif + initConstant(env, c, "IFF_ALLMULTI", IFF_ALLMULTI); +#if defined(IFF_AUTOMEDIA) + initConstant(env, c, "IFF_AUTOMEDIA", IFF_AUTOMEDIA); +#endif + initConstant(env, c, "IFF_BROADCAST", IFF_BROADCAST); + initConstant(env, c, "IFF_DEBUG", IFF_DEBUG); +#if defined(IFF_DYNAMIC) + initConstant(env, c, "IFF_DYNAMIC", IFF_DYNAMIC); +#endif + initConstant(env, c, "IFF_LOOPBACK", IFF_LOOPBACK); +#if defined(IFF_MASTER) + initConstant(env, c, "IFF_MASTER", IFF_MASTER); +#endif + initConstant(env, c, "IFF_MULTICAST", IFF_MULTICAST); + initConstant(env, c, "IFF_NOARP", IFF_NOARP); + initConstant(env, c, "IFF_NOTRAILERS", IFF_NOTRAILERS); + initConstant(env, c, "IFF_POINTOPOINT", IFF_POINTOPOINT); +#if defined(IFF_PORTSEL) + initConstant(env, c, "IFF_PORTSEL", IFF_PORTSEL); +#endif + initConstant(env, c, "IFF_PROMISC", IFF_PROMISC); + initConstant(env, c, "IFF_RUNNING", IFF_RUNNING); +#if defined(IFF_SLAVE) + initConstant(env, c, "IFF_SLAVE", IFF_SLAVE); +#endif + initConstant(env, c, "IFF_UP", IFF_UP); + initConstant(env, c, "IPPROTO_ICMP", IPPROTO_ICMP); + initConstant(env, c, "IPPROTO_ICMPV6", IPPROTO_ICMPV6); + initConstant(env, c, "IPPROTO_IP", IPPROTO_IP); + initConstant(env, c, "IPPROTO_IPV6", IPPROTO_IPV6); + initConstant(env, c, "IPPROTO_RAW", IPPROTO_RAW); + initConstant(env, c, "IPPROTO_TCP", IPPROTO_TCP); + initConstant(env, c, "IPPROTO_UDP", IPPROTO_UDP); + initConstant(env, c, "IPPROTO_ESP", IPPROTO_ESP); + initConstant(env, c, "IPV6_CHECKSUM", IPV6_CHECKSUM); + initConstant(env, c, "IPV6_MULTICAST_HOPS", IPV6_MULTICAST_HOPS); + initConstant(env, c, "IPV6_MULTICAST_IF", IPV6_MULTICAST_IF); + initConstant(env, c, "IPV6_MULTICAST_LOOP", IPV6_MULTICAST_LOOP); +#if defined(IPV6_PKTINFO) + initConstant(env, c, "IPV6_PKTINFO", IPV6_PKTINFO); +#endif +#if defined(IPV6_RECVDSTOPTS) + initConstant(env, c, "IPV6_RECVDSTOPTS", IPV6_RECVDSTOPTS); +#endif +#if defined(IPV6_RECVHOPLIMIT) + initConstant(env, c, "IPV6_RECVHOPLIMIT", IPV6_RECVHOPLIMIT); +#endif +#if defined(IPV6_RECVHOPOPTS) + initConstant(env, c, "IPV6_RECVHOPOPTS", IPV6_RECVHOPOPTS); +#endif +#if defined(IPV6_RECVPKTINFO) + initConstant(env, c, "IPV6_RECVPKTINFO", IPV6_RECVPKTINFO); +#endif +#if defined(IPV6_RECVRTHDR) + initConstant(env, c, "IPV6_RECVRTHDR", IPV6_RECVRTHDR); +#endif +#if defined(IPV6_RECVTCLASS) + initConstant(env, c, "IPV6_RECVTCLASS", IPV6_RECVTCLASS); +#endif +#if defined(IPV6_TCLASS) + initConstant(env, c, "IPV6_TCLASS", IPV6_TCLASS); +#endif + initConstant(env, c, "IPV6_UNICAST_HOPS", IPV6_UNICAST_HOPS); + initConstant(env, c, "IPV6_V6ONLY", IPV6_V6ONLY); + initConstant(env, c, "IP_MULTICAST_ALL", IP_MULTICAST_ALL); + initConstant(env, c, "IP_MULTICAST_IF", IP_MULTICAST_IF); + initConstant(env, c, "IP_MULTICAST_LOOP", IP_MULTICAST_LOOP); + initConstant(env, c, "IP_MULTICAST_TTL", IP_MULTICAST_TTL); + initConstant(env, c, "IP_RECVTOS", IP_RECVTOS); + initConstant(env, c, "IP_TOS", IP_TOS); + initConstant(env, c, "IP_TTL", IP_TTL); +#if defined(_LINUX_CAPABILITY_VERSION_3) + initConstant(env, c, "_LINUX_CAPABILITY_VERSION_3", _LINUX_CAPABILITY_VERSION_3); +#endif + initConstant(env, c, "MAP_FIXED", MAP_FIXED); + initConstant(env, c, "MAP_ANONYMOUS", MAP_ANONYMOUS); + initConstant(env, c, "MAP_POPULATE", MAP_POPULATE); + initConstant(env, c, "MAP_PRIVATE", MAP_PRIVATE); + initConstant(env, c, "MAP_SHARED", MAP_SHARED); +#if defined(MCAST_JOIN_GROUP) + initConstant(env, c, "MCAST_JOIN_GROUP", MCAST_JOIN_GROUP); +#endif +#if defined(MCAST_LEAVE_GROUP) + initConstant(env, c, "MCAST_LEAVE_GROUP", MCAST_LEAVE_GROUP); +#endif +#if defined(MCAST_JOIN_SOURCE_GROUP) + initConstant(env, c, "MCAST_JOIN_SOURCE_GROUP", MCAST_JOIN_SOURCE_GROUP); +#endif +#if defined(MCAST_LEAVE_SOURCE_GROUP) + initConstant(env, c, "MCAST_LEAVE_SOURCE_GROUP", MCAST_LEAVE_SOURCE_GROUP); +#endif +#if defined(MCAST_BLOCK_SOURCE) + initConstant(env, c, "MCAST_BLOCK_SOURCE", MCAST_BLOCK_SOURCE); +#endif +#if defined(MCAST_UNBLOCK_SOURCE) + initConstant(env, c, "MCAST_UNBLOCK_SOURCE", MCAST_UNBLOCK_SOURCE); +#endif + initConstant(env, c, "MCL_CURRENT", MCL_CURRENT); + initConstant(env, c, "MCL_FUTURE", MCL_FUTURE); +#if defined(MFD_CLOEXEC) + initConstant(env, c, "MFD_CLOEXEC", MFD_CLOEXEC); +#endif + initConstant(env, c, "MSG_CTRUNC", MSG_CTRUNC); + initConstant(env, c, "MSG_DONTROUTE", MSG_DONTROUTE); + initConstant(env, c, "MSG_EOR", MSG_EOR); + initConstant(env, c, "MSG_OOB", MSG_OOB); + initConstant(env, c, "MSG_PEEK", MSG_PEEK); + initConstant(env, c, "MSG_TRUNC", MSG_TRUNC); + initConstant(env, c, "MSG_WAITALL", MSG_WAITALL); + initConstant(env, c, "MS_ASYNC", MS_ASYNC); + initConstant(env, c, "MS_INVALIDATE", MS_INVALIDATE); + initConstant(env, c, "MS_SYNC", MS_SYNC); + initConstant(env, c, "NETLINK_NETFILTER", NETLINK_NETFILTER); + initConstant(env, c, "NETLINK_ROUTE", NETLINK_ROUTE); + initConstant(env, c, "NETLINK_INET_DIAG", NETLINK_INET_DIAG); + initConstant(env, c, "NETLINK_XFRM", NETLINK_XFRM); + initConstant(env, c, "NI_DGRAM", NI_DGRAM); + initConstant(env, c, "NI_NAMEREQD", NI_NAMEREQD); + initConstant(env, c, "NI_NOFQDN", NI_NOFQDN); + initConstant(env, c, "NI_NUMERICHOST", NI_NUMERICHOST); + initConstant(env, c, "NI_NUMERICSERV", NI_NUMERICSERV); + initConstant(env, c, "O_ACCMODE", O_ACCMODE); + initConstant(env, c, "O_APPEND", O_APPEND); + initConstant(env, c, "O_CLOEXEC", O_CLOEXEC); + initConstant(env, c, "O_CREAT", O_CREAT); + initConstant(env, c, "O_DIRECT", O_DIRECT); + initConstant(env, c, "O_EXCL", O_EXCL); + initConstant(env, c, "O_NOCTTY", O_NOCTTY); + initConstant(env, c, "O_NOFOLLOW", O_NOFOLLOW); + initConstant(env, c, "O_NONBLOCK", O_NONBLOCK); + initConstant(env, c, "O_RDONLY", O_RDONLY); + initConstant(env, c, "O_RDWR", O_RDWR); + initConstant(env, c, "O_SYNC", O_SYNC); + initConstant(env, c, "O_DSYNC", O_DSYNC); + initConstant(env, c, "O_TRUNC", O_TRUNC); + initConstant(env, c, "O_WRONLY", O_WRONLY); + initConstant(env, c, "POLLERR", POLLERR); + initConstant(env, c, "POLLHUP", POLLHUP); + initConstant(env, c, "POLLIN", POLLIN); + initConstant(env, c, "POLLNVAL", POLLNVAL); + initConstant(env, c, "POLLOUT", POLLOUT); + initConstant(env, c, "POLLPRI", POLLPRI); + initConstant(env, c, "POLLRDBAND", POLLRDBAND); + initConstant(env, c, "POLLRDNORM", POLLRDNORM); + initConstant(env, c, "POLLWRBAND", POLLWRBAND); + initConstant(env, c, "POLLWRNORM", POLLWRNORM); +#if defined(PR_CAP_AMBIENT) + initConstant(env, c, "PR_CAP_AMBIENT", PR_CAP_AMBIENT); +#endif +#if defined(PR_CAP_AMBIENT_RAISE) + initConstant(env, c, "PR_CAP_AMBIENT_RAISE", PR_CAP_AMBIENT_RAISE); +#endif +#if defined(PR_GET_DUMPABLE) + initConstant(env, c, "PR_GET_DUMPABLE", PR_GET_DUMPABLE); +#endif +#if defined(PR_SET_DUMPABLE) + initConstant(env, c, "PR_SET_DUMPABLE", PR_SET_DUMPABLE); +#endif +#if defined(PR_SET_NO_NEW_PRIVS) + initConstant(env, c, "PR_SET_NO_NEW_PRIVS", PR_SET_NO_NEW_PRIVS); +#endif + initConstant(env, c, "PROT_EXEC", PROT_EXEC); + initConstant(env, c, "PROT_NONE", PROT_NONE); + initConstant(env, c, "PROT_READ", PROT_READ); + initConstant(env, c, "PROT_WRITE", PROT_WRITE); + initConstant(env, c, "R_OK", R_OK); + initConstant(env, c, "RLIMIT_NOFILE", RLIMIT_NOFILE); +// NOTE: The RT_* constants are not preprocessor defines, they're enum +// members. The best we can do (barring UAPI / kernel version checks) is +// to hope they exist on all host linuxes we're building on. These +// constants have been around since 2.6.35 at least, so we should be ok. + initConstant(env, c, "RT_SCOPE_HOST", RT_SCOPE_HOST); + initConstant(env, c, "RT_SCOPE_LINK", RT_SCOPE_LINK); + initConstant(env, c, "RT_SCOPE_NOWHERE", RT_SCOPE_NOWHERE); + initConstant(env, c, "RT_SCOPE_SITE", RT_SCOPE_SITE); + initConstant(env, c, "RT_SCOPE_UNIVERSE", RT_SCOPE_UNIVERSE); + initConstant(env, c, "RTMGRP_IPV4_IFADDR", RTMGRP_IPV4_IFADDR); + initConstant(env, c, "RTMGRP_IPV4_MROUTE", RTMGRP_IPV4_MROUTE); + initConstant(env, c, "RTMGRP_IPV4_ROUTE", RTMGRP_IPV4_ROUTE); + initConstant(env, c, "RTMGRP_IPV4_RULE", RTMGRP_IPV4_RULE); + initConstant(env, c, "RTMGRP_IPV6_IFADDR", RTMGRP_IPV6_IFADDR); + initConstant(env, c, "RTMGRP_IPV6_IFINFO", RTMGRP_IPV6_IFINFO); + initConstant(env, c, "RTMGRP_IPV6_MROUTE", RTMGRP_IPV6_MROUTE); + initConstant(env, c, "RTMGRP_IPV6_PREFIX", RTMGRP_IPV6_PREFIX); + initConstant(env, c, "RTMGRP_IPV6_ROUTE", RTMGRP_IPV6_ROUTE); + initConstant(env, c, "RTMGRP_LINK", RTMGRP_LINK); + initConstant(env, c, "RTMGRP_NEIGH", RTMGRP_NEIGH); + initConstant(env, c, "RTMGRP_NOTIFY", RTMGRP_NOTIFY); + initConstant(env, c, "RTMGRP_TC", RTMGRP_TC); + initConstant(env, c, "SEEK_CUR", SEEK_CUR); + initConstant(env, c, "SEEK_END", SEEK_END); + initConstant(env, c, "SEEK_SET", SEEK_SET); + initConstant(env, c, "SHUT_RD", SHUT_RD); + initConstant(env, c, "SHUT_RDWR", SHUT_RDWR); + initConstant(env, c, "SHUT_WR", SHUT_WR); + initConstant(env, c, "SIGABRT", SIGABRT); + initConstant(env, c, "SIGALRM", SIGALRM); + initConstant(env, c, "SIGBUS", SIGBUS); + initConstant(env, c, "SIGCHLD", SIGCHLD); + initConstant(env, c, "SIGCONT", SIGCONT); + initConstant(env, c, "SIGFPE", SIGFPE); + initConstant(env, c, "SIGHUP", SIGHUP); + initConstant(env, c, "SIGILL", SIGILL); + initConstant(env, c, "SIGINT", SIGINT); + initConstant(env, c, "SIGIO", SIGIO); + initConstant(env, c, "SIGKILL", SIGKILL); + initConstant(env, c, "SIGPIPE", SIGPIPE); + initConstant(env, c, "SIGPROF", SIGPROF); +#if defined(SIGPWR) + initConstant(env, c, "SIGPWR", SIGPWR); +#endif + initConstant(env, c, "SIGQUIT", SIGQUIT); +#if defined(SIGRTMAX) + initConstant(env, c, "SIGRTMAX", SIGRTMAX); +#endif +#if defined(SIGRTMIN) + initConstant(env, c, "SIGRTMIN", SIGRTMIN); +#endif + initConstant(env, c, "SIGSEGV", SIGSEGV); +#if defined(SIGSTKFLT) + initConstant(env, c, "SIGSTKFLT", SIGSTKFLT); +#endif + initConstant(env, c, "SIGSTOP", SIGSTOP); + initConstant(env, c, "SIGSYS", SIGSYS); + initConstant(env, c, "SIGTERM", SIGTERM); + initConstant(env, c, "SIGTRAP", SIGTRAP); + initConstant(env, c, "SIGTSTP", SIGTSTP); + initConstant(env, c, "SIGTTIN", SIGTTIN); + initConstant(env, c, "SIGTTOU", SIGTTOU); + initConstant(env, c, "SIGURG", SIGURG); + initConstant(env, c, "SIGUSR1", SIGUSR1); + initConstant(env, c, "SIGUSR2", SIGUSR2); + initConstant(env, c, "SIGVTALRM", SIGVTALRM); + initConstant(env, c, "SIGWINCH", SIGWINCH); + initConstant(env, c, "SIGXCPU", SIGXCPU); + initConstant(env, c, "SIGXFSZ", SIGXFSZ); + initConstant(env, c, "SIOCGIFADDR", SIOCGIFADDR); + initConstant(env, c, "SIOCGIFBRDADDR", SIOCGIFBRDADDR); + initConstant(env, c, "SIOCGIFDSTADDR", SIOCGIFDSTADDR); + initConstant(env, c, "SIOCGIFNETMASK", SIOCGIFNETMASK); + initConstant(env, c, "SOCK_CLOEXEC", SOCK_CLOEXEC); + initConstant(env, c, "SOCK_DGRAM", SOCK_DGRAM); + initConstant(env, c, "SOCK_NONBLOCK", SOCK_NONBLOCK); + initConstant(env, c, "SOCK_RAW", SOCK_RAW); + initConstant(env, c, "SOCK_SEQPACKET", SOCK_SEQPACKET); + initConstant(env, c, "SOCK_STREAM", SOCK_STREAM); + initConstant(env, c, "SOL_SOCKET", SOL_SOCKET); +#if defined(SOL_UDP) + initConstant(env, c, "SOL_UDP", SOL_UDP); +#endif + initConstant(env, c, "SOL_PACKET", SOL_PACKET); +#if defined(SO_BINDTODEVICE) + initConstant(env, c, "SO_BINDTODEVICE", SO_BINDTODEVICE); +#endif + initConstant(env, c, "SO_BROADCAST", SO_BROADCAST); + initConstant(env, c, "SO_DEBUG", SO_DEBUG); +#if defined(SO_DOMAIN) + initConstant(env, c, "SO_DOMAIN", SO_DOMAIN); +#endif + initConstant(env, c, "SO_DONTROUTE", SO_DONTROUTE); + initConstant(env, c, "SO_ERROR", SO_ERROR); + initConstant(env, c, "SO_KEEPALIVE", SO_KEEPALIVE); + initConstant(env, c, "SO_LINGER", SO_LINGER); + initConstant(env, c, "SO_OOBINLINE", SO_OOBINLINE); +#if defined(SO_PASSCRED) + initConstant(env, c, "SO_PASSCRED", SO_PASSCRED); +#endif +#if defined(SO_PEERCRED) + initConstant(env, c, "SO_PEERCRED", SO_PEERCRED); +#endif +#if defined(SO_PROTOCOL) + initConstant(env, c, "SO_PROTOCOL", SO_PROTOCOL); +#endif + initConstant(env, c, "SO_RCVBUF", SO_RCVBUF); + initConstant(env, c, "SO_RCVLOWAT", SO_RCVLOWAT); + initConstant(env, c, "SO_RCVTIMEO", SO_RCVTIMEO); + initConstant(env, c, "SO_REUSEADDR", SO_REUSEADDR); + initConstant(env, c, "SO_SNDBUF", SO_SNDBUF); + initConstant(env, c, "SO_SNDLOWAT", SO_SNDLOWAT); + initConstant(env, c, "SO_SNDTIMEO", SO_SNDTIMEO); + initConstant(env, c, "SO_TYPE", SO_TYPE); +#if defined(PACKET_IGNORE_OUTGOING) + initConstant(env, c, "PACKET_IGNORE_OUTGOING", PACKET_IGNORE_OUTGOING); +#endif + initConstant(env, c, "SPLICE_F_MOVE", SPLICE_F_MOVE); + initConstant(env, c, "SPLICE_F_NONBLOCK", SPLICE_F_NONBLOCK); + initConstant(env, c, "SPLICE_F_MORE", SPLICE_F_MORE); + initConstant(env, c, "STDERR_FILENO", STDERR_FILENO); + initConstant(env, c, "STDIN_FILENO", STDIN_FILENO); + initConstant(env, c, "STDOUT_FILENO", STDOUT_FILENO); + initConstant(env, c, "ST_MANDLOCK", ST_MANDLOCK); + initConstant(env, c, "ST_NOATIME", ST_NOATIME); + initConstant(env, c, "ST_NODEV", ST_NODEV); + initConstant(env, c, "ST_NODIRATIME", ST_NODIRATIME); + initConstant(env, c, "ST_NOEXEC", ST_NOEXEC); + initConstant(env, c, "ST_NOSUID", ST_NOSUID); + initConstant(env, c, "ST_RDONLY", ST_RDONLY); + initConstant(env, c, "ST_RELATIME", ST_RELATIME); + initConstant(env, c, "ST_SYNCHRONOUS", ST_SYNCHRONOUS); + initConstant(env, c, "S_IFBLK", S_IFBLK); + initConstant(env, c, "S_IFCHR", S_IFCHR); + initConstant(env, c, "S_IFDIR", S_IFDIR); + initConstant(env, c, "S_IFIFO", S_IFIFO); + initConstant(env, c, "S_IFLNK", S_IFLNK); + initConstant(env, c, "S_IFMT", S_IFMT); + initConstant(env, c, "S_IFREG", S_IFREG); + initConstant(env, c, "S_IFSOCK", S_IFSOCK); + initConstant(env, c, "S_IRGRP", S_IRGRP); + initConstant(env, c, "S_IROTH", S_IROTH); + initConstant(env, c, "S_IRUSR", S_IRUSR); + initConstant(env, c, "S_IRWXG", S_IRWXG); + initConstant(env, c, "S_IRWXO", S_IRWXO); + initConstant(env, c, "S_IRWXU", S_IRWXU); + initConstant(env, c, "S_ISGID", S_ISGID); + initConstant(env, c, "S_ISUID", S_ISUID); + initConstant(env, c, "S_ISVTX", S_ISVTX); + initConstant(env, c, "S_IWGRP", S_IWGRP); + initConstant(env, c, "S_IWOTH", S_IWOTH); + initConstant(env, c, "S_IWUSR", S_IWUSR); + initConstant(env, c, "S_IXGRP", S_IXGRP); + initConstant(env, c, "S_IXOTH", S_IXOTH); + initConstant(env, c, "S_IXUSR", S_IXUSR); + initConstant(env, c, "TCP_NODELAY", TCP_NODELAY); +#if defined(TCP_USER_TIMEOUT) + initConstant(env, c, "TCP_USER_TIMEOUT", TCP_USER_TIMEOUT); +#endif + initConstant(env, c, "TIOCOUTQ", TIOCOUTQ); + initConstant(env, c, "UDP_ENCAP", UDP_ENCAP); + initConstant(env, c, "UDP_ENCAP_ESPINUDP_NON_IKE", UDP_ENCAP_ESPINUDP_NON_IKE); + initConstant(env, c, "UDP_ENCAP_ESPINUDP", UDP_ENCAP_ESPINUDP); +#if defined(UDP_GRO) + initConstant(env, c, "UDP_GRO", UDP_GRO); +#endif +#if defined(UDP_SEGMENT) + initConstant(env, c, "UDP_SEGMENT", UDP_SEGMENT); +#endif + // UNIX_PATH_MAX is mentioned in some versions of unix(7), but not actually declared. + initConstant(env, c, "UNIX_PATH_MAX", sizeof(sockaddr_un::sun_path)); + initConstant(env, c, "WCONTINUED", WCONTINUED); + initConstant(env, c, "WEXITED", WEXITED); + initConstant(env, c, "WNOHANG", WNOHANG); + initConstant(env, c, "WNOWAIT", WNOWAIT); + initConstant(env, c, "WSTOPPED", WSTOPPED); + initConstant(env, c, "WUNTRACED", WUNTRACED); + initConstant(env, c, "W_OK", W_OK); + initConstant(env, c, "XATTR_CREATE", XATTR_CREATE); + initConstant(env, c, "XATTR_REPLACE", XATTR_REPLACE); + initConstant(env, c, "X_OK", X_OK); + initConstant(env, c, "_SC_2_CHAR_TERM", _SC_2_CHAR_TERM); + initConstant(env, c, "_SC_2_C_BIND", _SC_2_C_BIND); + initConstant(env, c, "_SC_2_C_DEV", _SC_2_C_DEV); +#if defined(_SC_2_C_VERSION) + initConstant(env, c, "_SC_2_C_VERSION", _SC_2_C_VERSION); +#endif + initConstant(env, c, "_SC_2_FORT_DEV", _SC_2_FORT_DEV); + initConstant(env, c, "_SC_2_FORT_RUN", _SC_2_FORT_RUN); + initConstant(env, c, "_SC_2_LOCALEDEF", _SC_2_LOCALEDEF); + initConstant(env, c, "_SC_2_SW_DEV", _SC_2_SW_DEV); + initConstant(env, c, "_SC_2_UPE", _SC_2_UPE); + initConstant(env, c, "_SC_2_VERSION", _SC_2_VERSION); + initConstant(env, c, "_SC_AIO_LISTIO_MAX", _SC_AIO_LISTIO_MAX); + initConstant(env, c, "_SC_AIO_MAX", _SC_AIO_MAX); + initConstant(env, c, "_SC_AIO_PRIO_DELTA_MAX", _SC_AIO_PRIO_DELTA_MAX); + initConstant(env, c, "_SC_ARG_MAX", _SC_ARG_MAX); + initConstant(env, c, "_SC_ASYNCHRONOUS_IO", _SC_ASYNCHRONOUS_IO); + initConstant(env, c, "_SC_ATEXIT_MAX", _SC_ATEXIT_MAX); +#if defined(_SC_AVPHYS_PAGES) + initConstant(env, c, "_SC_AVPHYS_PAGES", _SC_AVPHYS_PAGES); +#endif + initConstant(env, c, "_SC_BC_BASE_MAX", _SC_BC_BASE_MAX); + initConstant(env, c, "_SC_BC_DIM_MAX", _SC_BC_DIM_MAX); + initConstant(env, c, "_SC_BC_SCALE_MAX", _SC_BC_SCALE_MAX); + initConstant(env, c, "_SC_BC_STRING_MAX", _SC_BC_STRING_MAX); + initConstant(env, c, "_SC_CHILD_MAX", _SC_CHILD_MAX); + initConstant(env, c, "_SC_CLK_TCK", _SC_CLK_TCK); + initConstant(env, c, "_SC_COLL_WEIGHTS_MAX", _SC_COLL_WEIGHTS_MAX); + initConstant(env, c, "_SC_DELAYTIMER_MAX", _SC_DELAYTIMER_MAX); + initConstant(env, c, "_SC_EXPR_NEST_MAX", _SC_EXPR_NEST_MAX); + initConstant(env, c, "_SC_FSYNC", _SC_FSYNC); + initConstant(env, c, "_SC_GETGR_R_SIZE_MAX", _SC_GETGR_R_SIZE_MAX); + initConstant(env, c, "_SC_GETPW_R_SIZE_MAX", _SC_GETPW_R_SIZE_MAX); + initConstant(env, c, "_SC_IOV_MAX", _SC_IOV_MAX); + initConstant(env, c, "_SC_JOB_CONTROL", _SC_JOB_CONTROL); + initConstant(env, c, "_SC_LINE_MAX", _SC_LINE_MAX); + initConstant(env, c, "_SC_LOGIN_NAME_MAX", _SC_LOGIN_NAME_MAX); + initConstant(env, c, "_SC_MAPPED_FILES", _SC_MAPPED_FILES); + initConstant(env, c, "_SC_MEMLOCK", _SC_MEMLOCK); + initConstant(env, c, "_SC_MEMLOCK_RANGE", _SC_MEMLOCK_RANGE); + initConstant(env, c, "_SC_MEMORY_PROTECTION", _SC_MEMORY_PROTECTION); + initConstant(env, c, "_SC_MESSAGE_PASSING", _SC_MESSAGE_PASSING); + initConstant(env, c, "_SC_MQ_OPEN_MAX", _SC_MQ_OPEN_MAX); + initConstant(env, c, "_SC_MQ_PRIO_MAX", _SC_MQ_PRIO_MAX); + initConstant(env, c, "_SC_NGROUPS_MAX", _SC_NGROUPS_MAX); + initConstant(env, c, "_SC_NPROCESSORS_CONF", _SC_NPROCESSORS_CONF); + initConstant(env, c, "_SC_NPROCESSORS_ONLN", _SC_NPROCESSORS_ONLN); + initConstant(env, c, "_SC_OPEN_MAX", _SC_OPEN_MAX); + initConstant(env, c, "_SC_PAGESIZE", _SC_PAGESIZE); + initConstant(env, c, "_SC_PAGE_SIZE", _SC_PAGE_SIZE); + initConstant(env, c, "_SC_PASS_MAX", _SC_PASS_MAX); +#if defined(_SC_PHYS_PAGES) + initConstant(env, c, "_SC_PHYS_PAGES", _SC_PHYS_PAGES); +#endif + initConstant(env, c, "_SC_PRIORITIZED_IO", _SC_PRIORITIZED_IO); + initConstant(env, c, "_SC_PRIORITY_SCHEDULING", _SC_PRIORITY_SCHEDULING); + initConstant(env, c, "_SC_REALTIME_SIGNALS", _SC_REALTIME_SIGNALS); + initConstant(env, c, "_SC_RE_DUP_MAX", _SC_RE_DUP_MAX); + initConstant(env, c, "_SC_RTSIG_MAX", _SC_RTSIG_MAX); + initConstant(env, c, "_SC_SAVED_IDS", _SC_SAVED_IDS); + initConstant(env, c, "_SC_SEMAPHORES", _SC_SEMAPHORES); + initConstant(env, c, "_SC_SEM_NSEMS_MAX", _SC_SEM_NSEMS_MAX); + initConstant(env, c, "_SC_SEM_VALUE_MAX", _SC_SEM_VALUE_MAX); + initConstant(env, c, "_SC_SHARED_MEMORY_OBJECTS", _SC_SHARED_MEMORY_OBJECTS); + initConstant(env, c, "_SC_SIGQUEUE_MAX", _SC_SIGQUEUE_MAX); + initConstant(env, c, "_SC_STREAM_MAX", _SC_STREAM_MAX); + initConstant(env, c, "_SC_SYNCHRONIZED_IO", _SC_SYNCHRONIZED_IO); + initConstant(env, c, "_SC_THREADS", _SC_THREADS); + initConstant(env, c, "_SC_THREAD_ATTR_STACKADDR", _SC_THREAD_ATTR_STACKADDR); + initConstant(env, c, "_SC_THREAD_ATTR_STACKSIZE", _SC_THREAD_ATTR_STACKSIZE); + initConstant(env, c, "_SC_THREAD_DESTRUCTOR_ITERATIONS", _SC_THREAD_DESTRUCTOR_ITERATIONS); + initConstant(env, c, "_SC_THREAD_KEYS_MAX", _SC_THREAD_KEYS_MAX); + initConstant(env, c, "_SC_THREAD_PRIORITY_SCHEDULING", _SC_THREAD_PRIORITY_SCHEDULING); + initConstant(env, c, "_SC_THREAD_PRIO_INHERIT", _SC_THREAD_PRIO_INHERIT); + initConstant(env, c, "_SC_THREAD_PRIO_PROTECT", _SC_THREAD_PRIO_PROTECT); + initConstant(env, c, "_SC_THREAD_SAFE_FUNCTIONS", _SC_THREAD_SAFE_FUNCTIONS); + initConstant(env, c, "_SC_THREAD_STACK_MIN", _SC_THREAD_STACK_MIN); + initConstant(env, c, "_SC_THREAD_THREADS_MAX", _SC_THREAD_THREADS_MAX); + initConstant(env, c, "_SC_TIMERS", _SC_TIMERS); + initConstant(env, c, "_SC_TIMER_MAX", _SC_TIMER_MAX); + initConstant(env, c, "_SC_TTY_NAME_MAX", _SC_TTY_NAME_MAX); + initConstant(env, c, "_SC_TZNAME_MAX", _SC_TZNAME_MAX); + initConstant(env, c, "_SC_VERSION", _SC_VERSION); + initConstant(env, c, "_SC_XBS5_ILP32_OFF32", _SC_XBS5_ILP32_OFF32); + initConstant(env, c, "_SC_XBS5_ILP32_OFFBIG", _SC_XBS5_ILP32_OFFBIG); + initConstant(env, c, "_SC_XBS5_LP64_OFF64", _SC_XBS5_LP64_OFF64); + initConstant(env, c, "_SC_XBS5_LPBIG_OFFBIG", _SC_XBS5_LPBIG_OFFBIG); + initConstant(env, c, "_SC_XOPEN_CRYPT", _SC_XOPEN_CRYPT); + initConstant(env, c, "_SC_XOPEN_ENH_I18N", _SC_XOPEN_ENH_I18N); + initConstant(env, c, "_SC_XOPEN_LEGACY", _SC_XOPEN_LEGACY); + initConstant(env, c, "_SC_XOPEN_REALTIME", _SC_XOPEN_REALTIME); + initConstant(env, c, "_SC_XOPEN_REALTIME_THREADS", _SC_XOPEN_REALTIME_THREADS); + initConstant(env, c, "_SC_XOPEN_SHM", _SC_XOPEN_SHM); + initConstant(env, c, "_SC_XOPEN_UNIX", _SC_XOPEN_UNIX); + initConstant(env, c, "_SC_XOPEN_VERSION", _SC_XOPEN_VERSION); + initConstant(env, c, "_SC_XOPEN_XCU_VERSION", _SC_XOPEN_XCU_VERSION); +} + +static JNINativeMethod gMethods[] = { + NATIVE_METHOD(OsConstants, initConstants, "()V"), +}; + +void register_android_system_OsConstants(JNIEnv* env) { + // [ravenwood-change] -- method moved to the nested class + jniRegisterNativeMethods(env, "android/system/OsConstants$Native", gMethods, NELEM(gMethods)); +} diff --git a/ravenwood/runtime-jni/ravenwood_runtime.cpp b/ravenwood/runtime-jni/ravenwood_runtime.cpp new file mode 100644 index 000000000000..34cf9f915677 --- /dev/null +++ b/ravenwood/runtime-jni/ravenwood_runtime.cpp @@ -0,0 +1,113 @@ +/* + * 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. + */ + +#include <fcntl.h> +#include <sys/stat.h> +#include <string.h> +#include <unistd.h> +#include <nativehelper/JNIHelp.h> +#include "jni.h" +#include "utils/Log.h" +#include "utils/misc.h" + +// Defined in ravenwood_os_constants.cpp +void register_android_system_OsConstants(JNIEnv* env); + +// ---- Exception related ---- + +static void throwErrnoException(JNIEnv* env, const char* functionName) { + int error = errno; + jniThrowErrnoException(env, functionName, error); +} + +template <typename rc_t> +static rc_t throwIfMinusOne(JNIEnv* env, const char* name, rc_t rc) { + if (rc == rc_t(-1)) { + throwErrnoException(env, name); + } + return rc; +} + +// ---- JNI methods ---- + +typedef void (*FreeFunction)(void*); + +static void nApplyFreeFunction(JNIEnv*, jclass, jlong freeFunction, jlong ptr) { + void* nativePtr = reinterpret_cast<void*>(static_cast<uintptr_t>(ptr)); + FreeFunction nativeFreeFunction + = reinterpret_cast<FreeFunction>(static_cast<uintptr_t>(freeFunction)); + nativeFreeFunction(nativePtr); +} + +static jint nFcntlInt(JNIEnv* env, jclass, jint fd, jint cmd, jint arg) { + return throwIfMinusOne(env, "fcntl", TEMP_FAILURE_RETRY(fcntl(fd, cmd, arg))); +} + +static jlong nLseek(JNIEnv* env, jclass, jint fd, jlong offset, jint whence) { + return throwIfMinusOne(env, "lseek", TEMP_FAILURE_RETRY(lseek(fd, offset, whence))); +} + +static jintArray nPipe2(JNIEnv* env, jclass, jint flags) { + int fds[2]; + throwIfMinusOne(env, "pipe2", TEMP_FAILURE_RETRY(pipe2(fds, flags))); + + jintArray result; + result = env->NewIntArray(2); + if (result == NULL) { + return NULL; /* out of memory error thrown */ + } + env->SetIntArrayRegion(result, 0, 2, fds); + return result; +} + +static jlong nDup(JNIEnv* env, jclass, jint fd) { + return throwIfMinusOne(env, "fcntl", TEMP_FAILURE_RETRY(fcntl(fd, F_DUPFD_CLOEXEC, 0))); +} + +// ---- Registration ---- + +static const JNINativeMethod sMethods[] = +{ + { "applyFreeFunction", "(JJ)V", (void*)nApplyFreeFunction }, + { "nFcntlInt", "(III)I", (void*)nFcntlInt }, + { "nLseek", "(IJI)J", (void*)nLseek }, + { "nPipe2", "(I)[I", (void*)nPipe2 }, + { "nDup", "(I)I", (void*)nDup }, +}; + +extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) +{ + JNIEnv* env = NULL; + jint result = -1; + + if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { + ALOGE("GetEnv failed!"); + return result; + } + ALOG_ASSERT(env, "Could not retrieve the env!"); + + ALOGI("%s: JNI_OnLoad", __FILE__); + + jint res = jniRegisterNativeMethods(env, "com/android/ravenwood/common/RavenwoodRuntimeNative", + sMethods, NELEM(sMethods)); + if (res < 0) { + return res; + } + + register_android_system_OsConstants(env); + + return JNI_VERSION_1_4; +} diff --git a/ravenwood/runtime-test/Android.bp b/ravenwood/runtime-test/Android.bp new file mode 100644 index 000000000000..410292001670 --- /dev/null +++ b/ravenwood/runtime-test/Android.bp @@ -0,0 +1,23 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +android_ravenwood_test { + name: "RavenwoodRuntimeTest", + + static_libs: [ + "androidx.annotation_annotation", + "androidx.test.ext.junit", + "androidx.test.rules", + ], + srcs: [ + "test/**/*.java", + ], + // sdk_version: "module_current", + auto_gen_config: true, +} diff --git a/ravenwood/runtime-test/test/com/android/ravenwood/runtimetest/OsConstantsTest.java b/ravenwood/runtime-test/test/com/android/ravenwood/runtimetest/OsConstantsTest.java new file mode 100644 index 000000000000..3332e24ea013 --- /dev/null +++ b/ravenwood/runtime-test/test/com/android/ravenwood/runtimetest/OsConstantsTest.java @@ -0,0 +1,444 @@ +/* + * 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.ravenwood.runtimetest; + +// Copied from libcore/luni/src/test/java/libcore/android/system/OsConstantsTest.java + +import static android.system.OsConstants.CAP_TO_INDEX; +import static android.system.OsConstants.CAP_TO_MASK; +import static android.system.OsConstants.S_ISBLK; +import static android.system.OsConstants.S_ISCHR; +import static android.system.OsConstants.S_ISDIR; +import static android.system.OsConstants.S_ISFIFO; +import static android.system.OsConstants.S_ISLNK; +import static android.system.OsConstants.S_ISREG; +import static android.system.OsConstants.S_ISSOCK; +import static android.system.OsConstants.WCOREDUMP; +import static android.system.OsConstants.WEXITSTATUS; +import static android.system.OsConstants.WIFEXITED; +import static android.system.OsConstants.WIFSIGNALED; +import static android.system.OsConstants.WIFSTOPPED; +import static android.system.OsConstants.WSTOPSIG; +import static android.system.OsConstants.WTERMSIG; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import android.system.OsConstants; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class OsConstantsTest { + + // http://b/15602893 + @Test + public void testBug15602893() { + assertTrue(OsConstants.RT_SCOPE_HOST > 0); + assertTrue(OsConstants.RT_SCOPE_LINK > 0); + assertTrue(OsConstants.RT_SCOPE_SITE > 0); + + assertTrue(OsConstants.IFA_F_TENTATIVE > 0); + } + + // introduced for http://b/30402085 + @Test + public void testTcpUserTimeoutIsDefined() { + assertTrue(OsConstants.TCP_USER_TIMEOUT > 0); + } + + /** + * Verifies equality assertions given in the documentation for + * {@link OsConstants#SOCK_CLOEXEC} and {@link OsConstants#SOCK_NONBLOCK}. + */ + @Test + public void testConstantsEqual() { + assertEquals(OsConstants.O_CLOEXEC, OsConstants.SOCK_CLOEXEC); + assertEquals(OsConstants.O_NONBLOCK, OsConstants.SOCK_NONBLOCK); + } + + @Test + public void test_CAP_constants() { + assertEquals(0, OsConstants.CAP_CHOWN); + assertEquals(1, OsConstants.CAP_DAC_OVERRIDE); + assertEquals(2, OsConstants.CAP_DAC_READ_SEARCH); + assertEquals(3, OsConstants.CAP_FOWNER); + assertEquals(4, OsConstants.CAP_FSETID); + assertEquals(5, OsConstants.CAP_KILL); + assertEquals(6, OsConstants.CAP_SETGID); + assertEquals(7, OsConstants.CAP_SETUID); + assertEquals(8, OsConstants.CAP_SETPCAP); + assertEquals(9, OsConstants.CAP_LINUX_IMMUTABLE); + assertEquals(10, OsConstants.CAP_NET_BIND_SERVICE); + assertEquals(11, OsConstants.CAP_NET_BROADCAST); + assertEquals(12, OsConstants.CAP_NET_ADMIN); + assertEquals(13, OsConstants.CAP_NET_RAW); + assertEquals(14, OsConstants.CAP_IPC_LOCK); + assertEquals(15, OsConstants.CAP_IPC_OWNER); + assertEquals(16, OsConstants.CAP_SYS_MODULE); + assertEquals(17, OsConstants.CAP_SYS_RAWIO); + assertEquals(18, OsConstants.CAP_SYS_CHROOT); + assertEquals(19, OsConstants.CAP_SYS_PTRACE); + assertEquals(20, OsConstants.CAP_SYS_PACCT); + assertEquals(21, OsConstants.CAP_SYS_ADMIN); + assertEquals(22, OsConstants.CAP_SYS_BOOT); + assertEquals(23, OsConstants.CAP_SYS_NICE); + assertEquals(24, OsConstants.CAP_SYS_RESOURCE); + assertEquals(25, OsConstants.CAP_SYS_TIME); + assertEquals(26, OsConstants.CAP_SYS_TTY_CONFIG); + assertEquals(27, OsConstants.CAP_MKNOD); + assertEquals(28, OsConstants.CAP_LEASE); + assertEquals(29, OsConstants.CAP_AUDIT_WRITE); + assertEquals(30, OsConstants.CAP_AUDIT_CONTROL); + assertEquals(31, OsConstants.CAP_SETFCAP); + assertEquals(32, OsConstants.CAP_MAC_OVERRIDE); + assertEquals(33, OsConstants.CAP_MAC_ADMIN); + assertEquals(34, OsConstants.CAP_SYSLOG); + assertEquals(35, OsConstants.CAP_WAKE_ALARM); + assertEquals(36, OsConstants.CAP_BLOCK_SUSPEND); + // last constant + assertEquals(40, OsConstants.CAP_LAST_CAP); + } + + @Test + public void test_CAP_TO_INDEX() { + assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_CHOWN)); + assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_DAC_OVERRIDE)); + assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_DAC_READ_SEARCH)); + assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_FOWNER)); + assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_FSETID)); + assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_KILL)); + assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_SETGID)); + assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_SETUID)); + assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_SETPCAP)); + assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_LINUX_IMMUTABLE)); + assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_NET_BIND_SERVICE)); + assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_NET_BROADCAST)); + assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_NET_ADMIN)); + assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_NET_RAW)); + assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_IPC_LOCK)); + assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_IPC_OWNER)); + assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_SYS_MODULE)); + assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_SYS_RAWIO)); + assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_SYS_CHROOT)); + assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_SYS_PTRACE)); + assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_SYS_PACCT)); + assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_SYS_ADMIN)); + assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_SYS_BOOT)); + assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_SYS_NICE)); + assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_SYS_RESOURCE)); + assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_SYS_TIME)); + assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_SYS_TTY_CONFIG)); + assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_MKNOD)); + assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_LEASE)); + assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_AUDIT_WRITE)); + assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_AUDIT_CONTROL)); + assertEquals(0, CAP_TO_INDEX(OsConstants.CAP_SETFCAP)); + assertEquals(1, CAP_TO_INDEX(OsConstants.CAP_MAC_OVERRIDE)); + assertEquals(1, CAP_TO_INDEX(OsConstants.CAP_MAC_ADMIN)); + assertEquals(1, CAP_TO_INDEX(OsConstants.CAP_SYSLOG)); + assertEquals(1, CAP_TO_INDEX(OsConstants.CAP_WAKE_ALARM)); + assertEquals(1, CAP_TO_INDEX(OsConstants.CAP_BLOCK_SUSPEND)); + } + + @Test + public void test_CAP_TO_MASK() { + assertEquals(1 << 0, CAP_TO_MASK(OsConstants.CAP_CHOWN)); + assertEquals(1 << 1, CAP_TO_MASK(OsConstants.CAP_DAC_OVERRIDE)); + assertEquals(1 << 2, CAP_TO_MASK(OsConstants.CAP_DAC_READ_SEARCH)); + assertEquals(1 << 3, CAP_TO_MASK(OsConstants.CAP_FOWNER)); + assertEquals(1 << 4, CAP_TO_MASK(OsConstants.CAP_FSETID)); + assertEquals(1 << 5, CAP_TO_MASK(OsConstants.CAP_KILL)); + assertEquals(1 << 6, CAP_TO_MASK(OsConstants.CAP_SETGID)); + assertEquals(1 << 7, CAP_TO_MASK(OsConstants.CAP_SETUID)); + assertEquals(1 << 8, CAP_TO_MASK(OsConstants.CAP_SETPCAP)); + assertEquals(1 << 9, CAP_TO_MASK(OsConstants.CAP_LINUX_IMMUTABLE)); + assertEquals(1 << 10, CAP_TO_MASK(OsConstants.CAP_NET_BIND_SERVICE)); + assertEquals(1 << 11, CAP_TO_MASK(OsConstants.CAP_NET_BROADCAST)); + assertEquals(1 << 12, CAP_TO_MASK(OsConstants.CAP_NET_ADMIN)); + assertEquals(1 << 13, CAP_TO_MASK(OsConstants.CAP_NET_RAW)); + assertEquals(1 << 14, CAP_TO_MASK(OsConstants.CAP_IPC_LOCK)); + assertEquals(1 << 15, CAP_TO_MASK(OsConstants.CAP_IPC_OWNER)); + assertEquals(1 << 16, CAP_TO_MASK(OsConstants.CAP_SYS_MODULE)); + assertEquals(1 << 17, CAP_TO_MASK(OsConstants.CAP_SYS_RAWIO)); + assertEquals(1 << 18, CAP_TO_MASK(OsConstants.CAP_SYS_CHROOT)); + assertEquals(1 << 19, CAP_TO_MASK(OsConstants.CAP_SYS_PTRACE)); + assertEquals(1 << 20, CAP_TO_MASK(OsConstants.CAP_SYS_PACCT)); + assertEquals(1 << 21, CAP_TO_MASK(OsConstants.CAP_SYS_ADMIN)); + assertEquals(1 << 22, CAP_TO_MASK(OsConstants.CAP_SYS_BOOT)); + assertEquals(1 << 23, CAP_TO_MASK(OsConstants.CAP_SYS_NICE)); + assertEquals(1 << 24, CAP_TO_MASK(OsConstants.CAP_SYS_RESOURCE)); + assertEquals(1 << 25, CAP_TO_MASK(OsConstants.CAP_SYS_TIME)); + assertEquals(1 << 26, CAP_TO_MASK(OsConstants.CAP_SYS_TTY_CONFIG)); + assertEquals(1 << 27, CAP_TO_MASK(OsConstants.CAP_MKNOD)); + assertEquals(1 << 28, CAP_TO_MASK(OsConstants.CAP_LEASE)); + assertEquals(1 << 29, CAP_TO_MASK(OsConstants.CAP_AUDIT_WRITE)); + assertEquals(1 << 30, CAP_TO_MASK(OsConstants.CAP_AUDIT_CONTROL)); + assertEquals(1 << 31, CAP_TO_MASK(OsConstants.CAP_SETFCAP)); + assertEquals(1 << 0, CAP_TO_MASK(OsConstants.CAP_MAC_OVERRIDE)); + assertEquals(1 << 1, CAP_TO_MASK(OsConstants.CAP_MAC_ADMIN)); + assertEquals(1 << 2, CAP_TO_MASK(OsConstants.CAP_SYSLOG)); + assertEquals(1 << 3, CAP_TO_MASK(OsConstants.CAP_WAKE_ALARM)); + assertEquals(1 << 4, CAP_TO_MASK(OsConstants.CAP_BLOCK_SUSPEND)); + } + + @Test + public void test_S_ISLNK() { + assertTrue(S_ISLNK(OsConstants.S_IFLNK)); + + assertFalse(S_ISLNK(OsConstants.S_IFBLK)); + assertFalse(S_ISLNK(OsConstants.S_IFCHR)); + assertFalse(S_ISLNK(OsConstants.S_IFDIR)); + assertFalse(S_ISLNK(OsConstants.S_IFIFO)); + assertFalse(S_ISLNK(OsConstants.S_IFMT)); + assertFalse(S_ISLNK(OsConstants.S_IFREG)); + assertFalse(S_ISLNK(OsConstants.S_IFSOCK)); + assertFalse(S_ISLNK(OsConstants.S_IRGRP)); + assertFalse(S_ISLNK(OsConstants.S_IROTH)); + assertFalse(S_ISLNK(OsConstants.S_IRUSR)); + assertFalse(S_ISLNK(OsConstants.S_IRWXG)); + assertFalse(S_ISLNK(OsConstants.S_IRWXO)); + assertFalse(S_ISLNK(OsConstants.S_IRWXU)); + assertFalse(S_ISLNK(OsConstants.S_ISGID)); + assertFalse(S_ISLNK(OsConstants.S_ISUID)); + assertFalse(S_ISLNK(OsConstants.S_ISVTX)); + assertFalse(S_ISLNK(OsConstants.S_IWGRP)); + assertFalse(S_ISLNK(OsConstants.S_IWOTH)); + assertFalse(S_ISLNK(OsConstants.S_IWUSR)); + assertFalse(S_ISLNK(OsConstants.S_IXGRP)); + assertFalse(S_ISLNK(OsConstants.S_IXOTH)); + assertFalse(S_ISLNK(OsConstants.S_IXUSR)); + } + + @Test + public void test_S_ISREG() { + assertTrue(S_ISREG(OsConstants.S_IFREG)); + + assertFalse(S_ISREG(OsConstants.S_IFBLK)); + assertFalse(S_ISREG(OsConstants.S_IFCHR)); + assertFalse(S_ISREG(OsConstants.S_IFDIR)); + assertFalse(S_ISREG(OsConstants.S_IFIFO)); + assertFalse(S_ISREG(OsConstants.S_IFLNK)); + assertFalse(S_ISREG(OsConstants.S_IFMT)); + assertFalse(S_ISREG(OsConstants.S_IFSOCK)); + assertFalse(S_ISREG(OsConstants.S_IRGRP)); + assertFalse(S_ISREG(OsConstants.S_IROTH)); + assertFalse(S_ISREG(OsConstants.S_IRUSR)); + assertFalse(S_ISREG(OsConstants.S_IRWXG)); + assertFalse(S_ISREG(OsConstants.S_IRWXO)); + assertFalse(S_ISREG(OsConstants.S_IRWXU)); + assertFalse(S_ISREG(OsConstants.S_ISGID)); + assertFalse(S_ISREG(OsConstants.S_ISUID)); + assertFalse(S_ISREG(OsConstants.S_ISVTX)); + assertFalse(S_ISREG(OsConstants.S_IWGRP)); + assertFalse(S_ISREG(OsConstants.S_IWOTH)); + assertFalse(S_ISREG(OsConstants.S_IWUSR)); + assertFalse(S_ISREG(OsConstants.S_IXGRP)); + assertFalse(S_ISREG(OsConstants.S_IXOTH)); + assertFalse(S_ISREG(OsConstants.S_IXUSR)); + } + + @Test + public void test_S_ISDIR() { + assertTrue(S_ISDIR(OsConstants.S_IFDIR)); + + assertFalse(S_ISDIR(OsConstants.S_IFBLK)); + assertFalse(S_ISDIR(OsConstants.S_IFCHR)); + assertFalse(S_ISDIR(OsConstants.S_IFIFO)); + assertFalse(S_ISDIR(OsConstants.S_IFLNK)); + assertFalse(S_ISDIR(OsConstants.S_IFMT)); + assertFalse(S_ISDIR(OsConstants.S_IFREG)); + assertFalse(S_ISDIR(OsConstants.S_IFSOCK)); + assertFalse(S_ISDIR(OsConstants.S_IRGRP)); + assertFalse(S_ISDIR(OsConstants.S_IROTH)); + assertFalse(S_ISDIR(OsConstants.S_IRUSR)); + assertFalse(S_ISDIR(OsConstants.S_IRWXG)); + assertFalse(S_ISDIR(OsConstants.S_IRWXO)); + assertFalse(S_ISDIR(OsConstants.S_IRWXU)); + assertFalse(S_ISDIR(OsConstants.S_ISGID)); + assertFalse(S_ISDIR(OsConstants.S_ISUID)); + assertFalse(S_ISDIR(OsConstants.S_ISVTX)); + assertFalse(S_ISDIR(OsConstants.S_IWGRP)); + assertFalse(S_ISDIR(OsConstants.S_IWOTH)); + assertFalse(S_ISDIR(OsConstants.S_IWUSR)); + assertFalse(S_ISDIR(OsConstants.S_IXGRP)); + assertFalse(S_ISDIR(OsConstants.S_IXOTH)); + assertFalse(S_ISDIR(OsConstants.S_IXUSR)); + } + + @Test + public void test_S_ISCHR() { + assertTrue(S_ISCHR(OsConstants.S_IFCHR)); + + assertFalse(S_ISCHR(OsConstants.S_IFBLK)); + assertFalse(S_ISCHR(OsConstants.S_IFDIR)); + assertFalse(S_ISCHR(OsConstants.S_IFIFO)); + assertFalse(S_ISCHR(OsConstants.S_IFLNK)); + assertFalse(S_ISCHR(OsConstants.S_IFMT)); + assertFalse(S_ISCHR(OsConstants.S_IFREG)); + assertFalse(S_ISCHR(OsConstants.S_IFSOCK)); + assertFalse(S_ISCHR(OsConstants.S_IRGRP)); + assertFalse(S_ISCHR(OsConstants.S_IROTH)); + assertFalse(S_ISCHR(OsConstants.S_IRUSR)); + assertFalse(S_ISCHR(OsConstants.S_IRWXG)); + assertFalse(S_ISCHR(OsConstants.S_IRWXO)); + assertFalse(S_ISCHR(OsConstants.S_IRWXU)); + assertFalse(S_ISCHR(OsConstants.S_ISGID)); + assertFalse(S_ISCHR(OsConstants.S_ISUID)); + assertFalse(S_ISCHR(OsConstants.S_ISVTX)); + assertFalse(S_ISCHR(OsConstants.S_IWGRP)); + assertFalse(S_ISCHR(OsConstants.S_IWOTH)); + assertFalse(S_ISCHR(OsConstants.S_IWUSR)); + assertFalse(S_ISCHR(OsConstants.S_IXGRP)); + assertFalse(S_ISCHR(OsConstants.S_IXOTH)); + assertFalse(S_ISCHR(OsConstants.S_IXUSR)); + } + + @Test + public void test_S_ISBLK() { + assertTrue (S_ISBLK(OsConstants.S_IFBLK)); + + assertFalse(S_ISBLK(OsConstants.S_IFCHR)); + assertFalse(S_ISBLK(OsConstants.S_IFDIR)); + assertFalse(S_ISBLK(OsConstants.S_IFIFO)); + assertFalse(S_ISBLK(OsConstants.S_IFLNK)); + assertFalse(S_ISBLK(OsConstants.S_IFMT)); + assertFalse(S_ISBLK(OsConstants.S_IFREG)); + assertFalse(S_ISBLK(OsConstants.S_IFSOCK)); + assertFalse(S_ISBLK(OsConstants.S_IRGRP)); + assertFalse(S_ISBLK(OsConstants.S_IROTH)); + assertFalse(S_ISBLK(OsConstants.S_IRUSR)); + assertFalse(S_ISBLK(OsConstants.S_IRWXG)); + assertFalse(S_ISBLK(OsConstants.S_IRWXO)); + assertFalse(S_ISBLK(OsConstants.S_IRWXU)); + assertFalse(S_ISBLK(OsConstants.S_ISGID)); + assertFalse(S_ISBLK(OsConstants.S_ISUID)); + assertFalse(S_ISBLK(OsConstants.S_ISVTX)); + assertFalse(S_ISBLK(OsConstants.S_IWGRP)); + assertFalse(S_ISBLK(OsConstants.S_IWOTH)); + assertFalse(S_ISBLK(OsConstants.S_IWUSR)); + assertFalse(S_ISBLK(OsConstants.S_IXGRP)); + assertFalse(S_ISBLK(OsConstants.S_IXOTH)); + assertFalse(S_ISBLK(OsConstants.S_IXUSR)); + } + + @Test + public void test_S_ISFIFO() { + assertTrue(S_ISFIFO(OsConstants.S_IFIFO)); + + assertFalse(S_ISFIFO(OsConstants.S_IFBLK)); + assertFalse(S_ISFIFO(OsConstants.S_IFCHR)); + assertFalse(S_ISFIFO(OsConstants.S_IFDIR)); + assertFalse(S_ISFIFO(OsConstants.S_IFLNK)); + assertFalse(S_ISFIFO(OsConstants.S_IFMT)); + assertFalse(S_ISFIFO(OsConstants.S_IFREG)); + assertFalse(S_ISFIFO(OsConstants.S_IFSOCK)); + assertFalse(S_ISFIFO(OsConstants.S_IRGRP)); + assertFalse(S_ISFIFO(OsConstants.S_IROTH)); + assertFalse(S_ISFIFO(OsConstants.S_IRUSR)); + assertFalse(S_ISFIFO(OsConstants.S_IRWXG)); + assertFalse(S_ISFIFO(OsConstants.S_IRWXO)); + assertFalse(S_ISFIFO(OsConstants.S_IRWXU)); + assertFalse(S_ISFIFO(OsConstants.S_ISGID)); + assertFalse(S_ISFIFO(OsConstants.S_ISUID)); + assertFalse(S_ISFIFO(OsConstants.S_ISVTX)); + assertFalse(S_ISFIFO(OsConstants.S_IWGRP)); + assertFalse(S_ISFIFO(OsConstants.S_IWOTH)); + assertFalse(S_ISFIFO(OsConstants.S_IWUSR)); + assertFalse(S_ISFIFO(OsConstants.S_IXGRP)); + assertFalse(S_ISFIFO(OsConstants.S_IXOTH)); + assertFalse(S_ISFIFO(OsConstants.S_IXUSR)); + } + + @Test + public void test_S_ISSOCK() { + assertTrue(S_ISSOCK(OsConstants.S_IFSOCK)); + + assertFalse(S_ISSOCK(OsConstants.S_IFBLK)); + assertFalse(S_ISSOCK(OsConstants.S_IFCHR)); + assertFalse(S_ISSOCK(OsConstants.S_IFDIR)); + assertFalse(S_ISSOCK(OsConstants.S_IFIFO)); + assertFalse(S_ISSOCK(OsConstants.S_IFLNK)); + assertFalse(S_ISSOCK(OsConstants.S_IFMT)); + assertFalse(S_ISSOCK(OsConstants.S_IFREG)); + assertFalse(S_ISSOCK(OsConstants.S_IRGRP)); + assertFalse(S_ISSOCK(OsConstants.S_IROTH)); + assertFalse(S_ISSOCK(OsConstants.S_IRUSR)); + assertFalse(S_ISSOCK(OsConstants.S_IRWXG)); + assertFalse(S_ISSOCK(OsConstants.S_IRWXO)); + assertFalse(S_ISSOCK(OsConstants.S_IRWXU)); + assertFalse(S_ISSOCK(OsConstants.S_ISGID)); + assertFalse(S_ISSOCK(OsConstants.S_ISUID)); + assertFalse(S_ISSOCK(OsConstants.S_ISVTX)); + assertFalse(S_ISSOCK(OsConstants.S_IWGRP)); + assertFalse(S_ISSOCK(OsConstants.S_IWOTH)); + assertFalse(S_ISSOCK(OsConstants.S_IWUSR)); + assertFalse(S_ISSOCK(OsConstants.S_IXGRP)); + assertFalse(S_ISSOCK(OsConstants.S_IXOTH)); + assertFalse(S_ISSOCK(OsConstants.S_IXUSR)); + } + + @Test + public void test_WEXITSTATUS() { + assertEquals(0, WEXITSTATUS(0x0000)); + assertEquals(0, WEXITSTATUS(0x00DE)); + assertEquals(0xF0, WEXITSTATUS(0xF000)); + assertEquals(0xAB, WEXITSTATUS(0xAB12)); + } + + @Test + public void test_WCOREDUMP() { + assertFalse(WCOREDUMP(0)); + assertTrue(WCOREDUMP(0x80)); + } + + @Test + public void test_WTERMSIG() { + assertEquals(0, WTERMSIG(0)); + assertEquals(0x7f, WTERMSIG(0x7f)); + } + + @Test + public void test_WSTOPSIG() { + assertEquals(0, WSTOPSIG(0x0000)); + assertEquals(0, WSTOPSIG(0x00DE)); + assertEquals(0xF0, WSTOPSIG(0xF000)); + assertEquals(0xAB, WSTOPSIG(0xAB12)); + } + + + @Test + public void test_WIFEXITED() { + assertTrue(WIFEXITED(0)); + assertFalse(WIFEXITED(0x7f)); + } + + @Test + public void test_WIFSTOPPED() { + assertFalse(WIFSTOPPED(0)); + assertTrue(WIFSTOPPED(0x7f)); + } + + @Test + public void test_WIFSIGNALED() { + assertFalse(WIFSIGNALED(0)); + assertTrue(WIFSIGNALED(1)); + } +} diff --git a/ravenwood/runtime-test/test/com/android/ravenwood/runtimetest/OsTest.java b/ravenwood/runtime-test/test/com/android/ravenwood/runtimetest/OsTest.java new file mode 100644 index 000000000000..b5038e68516d --- /dev/null +++ b/ravenwood/runtime-test/test/com/android/ravenwood/runtimetest/OsTest.java @@ -0,0 +1,122 @@ +/* + * 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.ravenwood.runtimetest; + +import static org.junit.Assert.assertEquals; + +import android.system.Os; +import android.system.OsConstants; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.android.ravenwood.common.JvmWorkaround; +import com.android.ravenwood.common.RavenwoodRuntimeNative; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.File; +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.RandomAccessFile; + +@RunWith(AndroidJUnit4.class) +public class OsTest { + public interface ConsumerWithThrow<T> { + void accept(T var1) throws Exception; + } + + private void withTestFile(ConsumerWithThrow<FileDescriptor> consumer) throws Exception { + File file = File.createTempFile("osTest", "bin"); + try (var raf = new RandomAccessFile(file, "rw")) { + var fd = raf.getFD(); + + try (var os = new FileOutputStream(fd)) { + os.write(1); + os.write(2); + os.write(3); + os.write(4); + + consumer.accept(fd); + } + } + } + + @Test + public void testLseek() throws Exception { + withTestFile((fd) -> { + assertEquals(4, Os.lseek(fd, 4, OsConstants.SEEK_SET)); + assertEquals(4, Os.lseek(fd, 0, OsConstants.SEEK_CUR)); + assertEquals(6, Os.lseek(fd, 2, OsConstants.SEEK_CUR)); + }); + } + + @Test + public void testDup() throws Exception { + withTestFile((fd) -> { + var dup = Os.dup(fd); + + checkAreDup(fd, dup); + }); + } + + @Test + public void testPipe2() throws Exception { + var fds = Os.pipe2(0); + + write(fds[1], 123); + assertEquals(123, read(fds[0])); + } + + @Test + public void testFcntlInt() throws Exception { + withTestFile((fd) -> { + var dupInt = Os.fcntlInt(fd, 0, 0); + + var dup = new FileDescriptor(); + JvmWorkaround.getInstance().setFdInt(dup, dupInt); + + checkAreDup(fd, dup); + }); + } + + private static void write(FileDescriptor fd, int oneByte) throws IOException { + // Create a dup to avoid closing the FD. + try (var dup = new FileOutputStream(RavenwoodRuntimeNative.dup(fd))) { + dup.write(oneByte); + } + } + + private static int read(FileDescriptor fd) throws IOException { + // Create a dup to avoid closing the FD. + try (var dup = new FileInputStream(RavenwoodRuntimeNative.dup(fd))) { + return dup.read(); + } + } + + private static void checkAreDup(FileDescriptor fd1, FileDescriptor fd2) throws Exception { + assertEquals(4, Os.lseek(fd1, 4, OsConstants.SEEK_SET)); + assertEquals(4, Os.lseek(fd1, 0, OsConstants.SEEK_CUR)); + + // Dup'ed FD shares the same position. + assertEquals(4, Os.lseek(fd2, 0, OsConstants.SEEK_CUR)); + + assertEquals(6, Os.lseek(fd1, 2, OsConstants.SEEK_CUR)); + assertEquals(6, Os.lseek(fd2, 0, OsConstants.SEEK_CUR)); + } +} diff --git a/services/core/java/com/android/server/wearable/WearableSensingManagerService.java b/services/core/java/com/android/server/wearable/WearableSensingManagerService.java index 110100ac735b..8d14c1d64b9c 100644 --- a/services/core/java/com/android/server/wearable/WearableSensingManagerService.java +++ b/services/core/java/com/android/server/wearable/WearableSensingManagerService.java @@ -35,6 +35,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManagerInternal; import android.os.Binder; +import android.os.Build; import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; import android.os.RemoteCallback; @@ -189,6 +190,9 @@ public class WearableSensingManagerService extends @Override protected int getMaximumTemporaryServiceDurationMs() { + if (Build.isDebuggable()) { + return Integer.MAX_VALUE; + } return MAX_TEMPORARY_SERVICE_DURATION_MS; } |