summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/os/Handler.java1
-rw-r--r--core/java/android/os/HandlerThread.java1
-rw-r--r--core/java/android/os/Looper.java45
-rw-r--r--core/java/android/os/Message.java1
-rw-r--r--core/java/android/os/MessageQueue.java6
-rw-r--r--core/java/android/os/Process.java58
-rw-r--r--core/java/android/os/SystemClock.java20
-rw-r--r--core/java/android/os/ThreadLocalWorkSource.java1
-rw-r--r--ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodThrow.java9
-rw-r--r--ravenwood/framework-minus-apex-ravenwood-policies.txt1
-rw-r--r--ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java22
-rw-r--r--ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java23
-rw-r--r--ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java4
-rw-r--r--ravenwood/ravenwood-annotation-allowed-classes.txt7
-rw-r--r--ravenwood/ravenwood-standard-options.txt1
-rw-r--r--tools/hoststubgen/hoststubgen/framework-policy-override.txt3
-rw-r--r--tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/MessageQueue_host.java94
-rw-r--r--tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java2
18 files changed, 269 insertions, 30 deletions
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index 22d6fcdc7983..92b630f3063a 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -63,6 +63,7 @@ import java.lang.reflect.Modifier;
* your new thread. The given Runnable or Message will then be scheduled
* in the Handler's message queue and processed when appropriate.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class Handler {
/*
* Set this flag to true to detect anonymous, local or member classes
diff --git a/core/java/android/os/HandlerThread.java b/core/java/android/os/HandlerThread.java
index 4dd797a70fcb..fcd57313a28d 100644
--- a/core/java/android/os/HandlerThread.java
+++ b/core/java/android/os/HandlerThread.java
@@ -25,6 +25,7 @@ import android.annotation.Nullable;
* <p>
* Note that just like with a regular {@link Thread}, {@link #start()} must still be called.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index 712d328e9dc9..ddf2b61324ad 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -24,6 +24,8 @@ import android.util.Printer;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
+import java.util.Objects;
+
/**
* Class used to run a message loop for a thread. Threads by default do
* not have a message loop associated with them; to create one, call
@@ -54,6 +56,7 @@ import android.util.proto.ProtoOutputStream;
* }
* }</pre>
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public final class Looper {
/*
* API Implementation Note:
@@ -144,6 +147,30 @@ public final class Looper {
}
/**
+ * Force the application's main looper to the given value. The main looper is typically
+ * configured automatically by the OS, so this capability is only intended to enable testing.
+ *
+ * @hide
+ */
+ public static void setMainLooperForTest(@NonNull Looper looper) {
+ synchronized (Looper.class) {
+ sMainLooper = Objects.requireNonNull(looper);
+ }
+ }
+
+ /**
+ * Clear the application's main looper to be undefined. The main looper is typically
+ * configured automatically by the OS, so this capability is only intended to enable testing.
+ *
+ * @hide
+ */
+ public static void clearMainLooperForTest() {
+ synchronized (Looper.class) {
+ sMainLooper = null;
+ }
+ }
+
+ /**
* Set the transaction observer for all Loopers in this process.
*
* @hide
@@ -282,11 +309,7 @@ public final class Looper {
// Allow overriding a threshold with a system prop. e.g.
// adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
- final int thresholdOverride =
- SystemProperties.getInt("log.looper."
- + Process.myUid() + "."
- + Thread.currentThread().getName()
- + ".slow", -1);
+ final int thresholdOverride = getThresholdOverride();
me.mSlowDeliveryDetected = false;
@@ -297,6 +320,18 @@ public final class Looper {
}
}
+ @android.ravenwood.annotation.RavenwoodReplace
+ private static int getThresholdOverride() {
+ return SystemProperties.getInt("log.looper."
+ + Process.myUid() + "."
+ + Thread.currentThread().getName()
+ + ".slow", -1);
+ }
+
+ private static int getThresholdOverride$ravenwood() {
+ return -1;
+ }
+
private static boolean showSlowLog(long threshold, long measureStart, long measureEnd,
String what, Message msg) {
final long actualTime = measureEnd - measureStart;
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index 72fb4ae03a63..da647e2b78cb 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -33,6 +33,7 @@ import com.android.internal.annotations.VisibleForTesting;
* {@link Handler#obtainMessage Handler.obtainMessage()} methods, which will pull
* them from a pool of recycled objects.</p>
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public final class Message implements Parcelable {
/**
* User-defined message code so that the recipient can identify
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index 9d8a71bf4abd..c60f949da408 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -40,6 +40,9 @@ import java.util.ArrayList;
* <p>You can retrieve the MessageQueue for the current thread with
* {@link Looper#myQueue() Looper.myQueue()}.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
+@android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
+ "com.android.hoststubgen.nativesubstitution.MessageQueue_host")
public final class MessageQueue {
private static final String TAG = "MessageQueue";
private static final boolean DEBUG = false;
@@ -194,6 +197,7 @@ public final class MessageQueue {
* @see OnFileDescriptorEventListener
* @see #removeOnFileDescriptorEventListener
*/
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class)
public void addOnFileDescriptorEventListener(@NonNull FileDescriptor fd,
@OnFileDescriptorEventListener.Events int events,
@NonNull OnFileDescriptorEventListener listener) {
@@ -221,6 +225,7 @@ public final class MessageQueue {
* @see OnFileDescriptorEventListener
* @see #addOnFileDescriptorEventListener
*/
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class)
public void removeOnFileDescriptorEventListener(@NonNull FileDescriptor fd) {
if (fd == null) {
throw new IllegalArgumentException("fd must not be null");
@@ -231,6 +236,7 @@ public final class MessageQueue {
}
}
+ @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class)
private void updateOnFileDescriptorEventListenerLocked(FileDescriptor fd, int events,
OnFileDescriptorEventListener listener) {
final int fdNum = fd.getInt$();
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 13572fb1bbbb..11660f9930c3 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -842,15 +842,19 @@ public class Process {
return "amd64".equals(System.getProperty("os.arch"));
}
- private static SomeArgs sIdentity$ravenwood;
+ private static ThreadLocal<SomeArgs> sIdentity$ravenwood;
/** @hide */
@android.ravenwood.annotation.RavenwoodKeep
- public static void init$ravenwood(int uid, int pid) {
- final SomeArgs args = SomeArgs.obtain();
- args.argi1 = uid;
- args.argi2 = pid;
- sIdentity$ravenwood = args;
+ public static void init$ravenwood(final int uid, final int pid) {
+ sIdentity$ravenwood = ThreadLocal.withInitial(() -> {
+ final SomeArgs args = SomeArgs.obtain();
+ args.argi1 = uid;
+ args.argi2 = pid;
+ args.argi3 = Long.hashCode(Thread.currentThread().getId());
+ args.argi4 = THREAD_PRIORITY_DEFAULT;
+ return args;
+ });
}
/** @hide */
@@ -870,7 +874,7 @@ public class Process {
/** @hide */
public static final int myPid$ravenwood() {
- return Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).argi2;
+ return Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get().argi2;
}
/**
@@ -886,10 +890,16 @@ public class Process {
* Returns the identifier of the calling thread, which be used with
* {@link #setThreadPriority(int, int)}.
*/
+ @android.ravenwood.annotation.RavenwoodReplace
public static final int myTid() {
return Os.gettid();
}
+ /** @hide */
+ public static final int myTid$ravenwood() {
+ return Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get().argi3;
+ }
+
/**
* Returns the identifier of this process's uid. This is the kernel uid
* that the process is running under, which is the identity of its
@@ -903,7 +913,7 @@ public class Process {
/** @hide */
public static final int myUid$ravenwood() {
- return Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).argi1;
+ return Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get().argi1;
}
/**
@@ -1086,9 +1096,22 @@ public class Process {
* not have permission to modify the given thread, or to use the given
* priority.
*/
+ @android.ravenwood.annotation.RavenwoodReplace
public static final native void setThreadPriority(int tid, int priority)
throws IllegalArgumentException, SecurityException;
+ /** @hide */
+ public static final void setThreadPriority$ravenwood(int tid, int priority) {
+ final SomeArgs args =
+ Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get();
+ if (args.argi3 == tid) {
+ args.argi4 = priority;
+ } else {
+ throw new UnsupportedOperationException(
+ "Cross-thread priority management not yet available in Ravenwood");
+ }
+ }
+
/**
* Call with 'false' to cause future calls to {@link #setThreadPriority(int)} to
* throw an exception if passed a background-level thread priority. This is only
@@ -1226,9 +1249,15 @@ public class Process {
*
* @see #setThreadPriority(int, int)
*/
+ @android.ravenwood.annotation.RavenwoodReplace
public static final native void setThreadPriority(int priority)
throws IllegalArgumentException, SecurityException;
+ /** @hide */
+ public static final void setThreadPriority$ravenwood(int priority) {
+ setThreadPriority(myTid(), priority);
+ }
+
/**
* Return the current priority of a thread, based on Linux priorities.
*
@@ -1242,9 +1271,22 @@ public class Process {
* @throws IllegalArgumentException Throws IllegalArgumentException if
* <var>tid</var> does not exist.
*/
+ @android.ravenwood.annotation.RavenwoodReplace
public static final native int getThreadPriority(int tid)
throws IllegalArgumentException;
+ /** @hide */
+ public static final int getThreadPriority$ravenwood(int tid) {
+ final SomeArgs args =
+ Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get();
+ if (args.argi3 == tid) {
+ return args.argi4;
+ } else {
+ throw new UnsupportedOperationException(
+ "Cross-thread priority management not yet available in Ravenwood");
+ }
+ }
+
/**
* Return the current scheduling policy of a thread, based on Linux.
*
diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java
index 49a0bd3289aa..2e6cccbd435f 100644
--- a/core/java/android/os/SystemClock.java
+++ b/core/java/android/os/SystemClock.java
@@ -110,6 +110,11 @@ public final class SystemClock {
private static volatile IAlarmManager sIAlarmManager;
/**
+ * Since {@code nanoTime()} is arbitrary, anchor our Ravenwood clocks against it.
+ */
+ private static final long sAnchorNanoTime$ravenwood = System.nanoTime();
+
+ /**
* This class is uninstantiable.
*/
@UnsupportedAppUsage
@@ -193,9 +198,7 @@ public final class SystemClock {
/** @hide */
public static long uptimeMillis$ravenwood() {
- // Ravenwood booted in Jan 2023, and has been in deep sleep for one week
- return System.currentTimeMillis() - (1672556400L * 1_000)
- - (DateUtils.WEEK_IN_MILLIS * 1_000);
+ return uptimeNanos() / 1_000_000;
}
/**
@@ -210,9 +213,7 @@ public final class SystemClock {
/** @hide */
public static long uptimeNanos$ravenwood() {
- // Ravenwood booted in Jan 2023, and has been in deep sleep for one week
- return System.nanoTime() - (1672556400L * 1_000_000_000)
- - (DateUtils.WEEK_IN_MILLIS * 1_000_000_000);
+ return System.nanoTime() - sAnchorNanoTime$ravenwood;
}
/**
@@ -241,8 +242,7 @@ public final class SystemClock {
/** @hide */
public static long elapsedRealtime$ravenwood() {
- // Ravenwood booted in Jan 2023, and has been in deep sleep for one week
- return System.currentTimeMillis() - (1672556400L * 1_000);
+ return elapsedRealtimeNanos() / 1_000_000;
}
/**
@@ -271,8 +271,8 @@ public final class SystemClock {
/** @hide */
public static long elapsedRealtimeNanos$ravenwood() {
- // Ravenwood booted in Jan 2023, and has been in deep sleep for one week
- return System.nanoTime() - (1672556400L * 1_000_000_000);
+ // Elapsed realtime is uptime plus an hour that we've been "asleep"
+ return uptimeNanos() + (DateUtils.HOUR_IN_MILLIS * 1_000_000);
}
/**
diff --git a/core/java/android/os/ThreadLocalWorkSource.java b/core/java/android/os/ThreadLocalWorkSource.java
index e9adb209ddc6..7c4a2be09bf8 100644
--- a/core/java/android/os/ThreadLocalWorkSource.java
+++ b/core/java/android/os/ThreadLocalWorkSource.java
@@ -37,6 +37,7 @@ package android.os;
*
* @hide Only for use within system server.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public final class ThreadLocalWorkSource {
public static final int UID_NONE = Message.UID_NONE;
private static final ThreadLocal<int []> sWorkSourceUid =
diff --git a/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodThrow.java b/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodThrow.java
index a234a9b6fc7c..0bb1f39cd453 100644
--- a/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodThrow.java
+++ b/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodThrow.java
@@ -34,4 +34,13 @@ import java.lang.annotation.Target;
@Target({METHOD, CONSTRUCTOR})
@Retention(RetentionPolicy.CLASS)
public @interface RavenwoodThrow {
+ /**
+ * One or more classes that aren't yet supported by Ravenwood, which is why this method throws.
+ */
+ Class<?>[] blockedBy() default {};
+
+ /**
+ * General free-form description of why this method throws.
+ */
+ String reason() default "";
}
diff --git a/ravenwood/framework-minus-apex-ravenwood-policies.txt b/ravenwood/framework-minus-apex-ravenwood-policies.txt
index 48e93280f73f..b92663c83889 100644
--- a/ravenwood/framework-minus-apex-ravenwood-policies.txt
+++ b/ravenwood/framework-minus-apex-ravenwood-policies.txt
@@ -109,6 +109,7 @@ class android.os.Bundle stubclass
class android.os.PersistableBundle stubclass
# Misc
+class android.os.HandlerExecutor stubclass
class android.os.PatternMatcher stubclass
class android.os.ParcelUuid stubclass
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 1caef26d50eb..be0c09ee4a25 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
@@ -16,13 +16,35 @@
package android.platform.test.ravenwood;
+import android.os.HandlerThread;
+import android.os.Looper;
+
+import java.util.Objects;
+
public class RavenwoodRuleImpl {
+ private static final String MAIN_THREAD_NAME = "RavenwoodMain";
+
+ public static boolean isUnderRavenwood() {
+ return true;
+ }
+
public static void init(RavenwoodRule rule) {
android.os.Process.init$ravenwood(rule.mUid, rule.mPid);
android.os.Binder.init$ravenwood();
+
+ if (rule.mProvideMainThread) {
+ final HandlerThread main = new HandlerThread(MAIN_THREAD_NAME);
+ main.start();
+ Looper.setMainLooperForTest(main.getLooper());
+ }
}
public static void reset(RavenwoodRule rule) {
+ if (rule.mProvideMainThread) {
+ Looper.getMainLooper().quit();
+ Looper.clearMainLooperForTest();
+ }
+
android.os.Process.reset$ravenwood();
android.os.Binder.reset$ravenwood();
}
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
index 79f9e58aaa1a..9db5b9895749 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
@@ -34,6 +34,8 @@ import java.util.concurrent.atomic.AtomicInteger;
public class RavenwoodRule implements TestRule {
private static AtomicInteger sNextPid = new AtomicInteger(100);
+ private static final boolean IS_UNDER_RAVENWOOD = RavenwoodRuleImpl.isUnderRavenwood();
+
private static final int SYSTEM_UID = 1000;
private static final int NOBODY_UID = 9999;
private static final int FIRST_APPLICATION_UID = 10000;
@@ -45,6 +47,8 @@ public class RavenwoodRule implements TestRule {
int mUid = NOBODY_UID;
int mPid = sNextPid.getAndIncrement();
+ boolean mProvideMainThread = false;
+
public RavenwoodRule() {
}
@@ -72,6 +76,15 @@ public class RavenwoodRule implements TestRule {
return this;
}
+ /**
+ * Configure a "main" thread to be available for the duration of the test, as defined
+ * by {@code Looper.getMainLooper()}. Has no effect under non-Ravenwood environments.
+ */
+ public Builder setProvideMainThread(boolean provideMainThread) {
+ mRule.mProvideMainThread = provideMainThread;
+ return this;
+ }
+
public RavenwoodRule build() {
return mRule;
}
@@ -81,8 +94,7 @@ public class RavenwoodRule implements TestRule {
* Return if the current process is running under a Ravenwood test environment.
*/
public boolean isUnderRavenwood() {
- // TODO: give ourselves a better environment signal
- return System.getProperty("java.class.path").contains("ravenwood");
+ return IS_UNDER_RAVENWOOD;
}
@Override
@@ -90,17 +102,16 @@ public class RavenwoodRule implements TestRule {
return new Statement() {
@Override
public void evaluate() throws Throwable {
- final boolean isUnderRavenwood = isUnderRavenwood();
if (description.getAnnotation(IgnoreUnderRavenwood.class) != null) {
- Assume.assumeFalse(isUnderRavenwood);
+ Assume.assumeFalse(IS_UNDER_RAVENWOOD);
}
- if (isUnderRavenwood) {
+ if (IS_UNDER_RAVENWOOD) {
RavenwoodRuleImpl.init(RavenwoodRule.this);
}
try {
base.evaluate();
} finally {
- if (isUnderRavenwood) {
+ if (IS_UNDER_RAVENWOOD) {
RavenwoodRuleImpl.reset(RavenwoodRule.this);
}
}
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 ecaff8084888..fb71e9d1ac6f 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
+++ b/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
@@ -17,6 +17,10 @@
package android.platform.test.ravenwood;
public class RavenwoodRuleImpl {
+ public static boolean isUnderRavenwood() {
+ return false;
+ }
+
public static void init(RavenwoodRule rule) {
// Must be provided by impl to reference runtime internals
throw new UnsupportedOperationException();
diff --git a/ravenwood/ravenwood-annotation-allowed-classes.txt b/ravenwood/ravenwood-annotation-allowed-classes.txt
index a791f682fecf..e943786a5369 100644
--- a/ravenwood/ravenwood-annotation-allowed-classes.txt
+++ b/ravenwood/ravenwood-annotation-allowed-classes.txt
@@ -12,9 +12,16 @@ android.util.Xml
android.os.Binder
android.os.Binder$IdentitySupplier
+android.os.Handler
+android.os.HandlerExecutor
+android.os.HandlerThread
android.os.IBinder
+android.os.Looper
+android.os.Message
+android.os.MessageQueue
android.os.Process
android.os.SystemClock
+android.os.ThreadLocalWorkSource
android.os.UserHandle
android.content.ClipData
diff --git a/ravenwood/ravenwood-standard-options.txt b/ravenwood/ravenwood-standard-options.txt
index f842f33bc95b..8ad21fa53a51 100644
--- a/ravenwood/ravenwood-standard-options.txt
+++ b/ravenwood/ravenwood-standard-options.txt
@@ -7,6 +7,7 @@
# Uncomment below lines to enable each feature.
# --enable-non-stub-method-check
+--no-non-stub-method-check
#--default-method-call-hook
# com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
diff --git a/tools/hoststubgen/hoststubgen/framework-policy-override.txt b/tools/hoststubgen/hoststubgen/framework-policy-override.txt
index 493ad56a5cbb..af3789e270a4 100644
--- a/tools/hoststubgen/hoststubgen/framework-policy-override.txt
+++ b/tools/hoststubgen/hoststubgen/framework-policy-override.txt
@@ -100,3 +100,6 @@ class android.os.BadTypeParcelableException stubclass
class android.os.BaseBundle stubclass
class android.os.Bundle stubclass
class android.os.PersistableBundle stubclass
+
+class android.os.MessageQueue stubclass
+class android.os.MessageQueue !com.android.hoststubgen.nativesubstitution.MessageQueue_host
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/MessageQueue_host.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/MessageQueue_host.java
new file mode 100644
index 000000000000..2e47d48f4fa0
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/MessageQueue_host.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.hoststubgen.nativesubstitution;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+public class MessageQueue_host {
+ private static final AtomicLong sNextId = new AtomicLong(1);
+ private static final Map<Long, MessageQueue_host> sInstances = new ConcurrentHashMap<>();
+
+ private boolean mDeleted = false;
+
+ private final Object mPoller = new Object();
+ private volatile boolean mPolling;
+
+ private void validate() {
+ if (mDeleted) {
+ // TODO: Put more info
+ throw new RuntimeException("MessageQueue already destroyed");
+ }
+ }
+
+ private static MessageQueue_host getInstance(long id) {
+ MessageQueue_host q = sInstances.get(id);
+ if (q == null) {
+ throw new RuntimeException("MessageQueue doesn't exist with id=" + id);
+ }
+ q.validate();
+ return q;
+ }
+
+ public static long nativeInit() {
+ final long id = sNextId.getAndIncrement();
+ final MessageQueue_host q = new MessageQueue_host();
+ sInstances.put(id, q);
+ return id;
+ }
+
+ public static void nativeDestroy(long ptr) {
+ getInstance(ptr).mDeleted = true;
+ sInstances.remove(ptr);
+ }
+
+ public static void nativePollOnce(android.os.MessageQueue queue, long ptr, int timeoutMillis) {
+ var q = getInstance(ptr);
+ synchronized (q.mPoller) {
+ q.mPolling = true;
+ try {
+ if (timeoutMillis == 0) {
+ // Calling epoll_wait() with 0 returns immediately
+ } else if (timeoutMillis == -1) {
+ q.mPoller.wait();
+ } else {
+ q.mPoller.wait(timeoutMillis);
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ q.mPolling = false;
+ }
+ }
+
+ public static void nativeWake(long ptr) {
+ var q = getInstance(ptr);
+ synchronized (q.mPoller) {
+ q.mPoller.notifyAll();
+ }
+ }
+
+ public static boolean nativeIsPolling(long ptr) {
+ var q = getInstance(ptr);
+ return q.mPolling;
+ }
+
+ public static void nativeSetFileDescriptorEvents(long ptr, int fd, int events) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java
index 4a3a79803b65..98d5778f047e 100644
--- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java
+++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java
@@ -36,7 +36,7 @@ public class Parcel_host {
private Parcel_host() {
}
- private static final AtomicLong sNextId = new AtomicLong(0);
+ private static final AtomicLong sNextId = new AtomicLong(1);
private static final Map<Long, Parcel_host> sInstances = new ConcurrentHashMap<>();