summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java25
-rw-r--r--services/core/java/com/android/server/soundtrigger_middleware/UptimeTimer.java90
-rw-r--r--services/tests/servicestests/src/com/android/server/soundtrigger_middleware/UptimeTimerTest.java59
3 files changed, 157 insertions, 17 deletions
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java
index 212f81f72b24..086ebc99eff7 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java
@@ -27,8 +27,6 @@ import android.os.SystemProperties;
import android.util.Log;
import java.util.Objects;
-import java.util.Timer;
-import java.util.TimerTask;
/**
* An {@link ISoundTriggerHw2} decorator that would enforce deadlines on all calls and reboot the
@@ -38,14 +36,12 @@ public class SoundTriggerHw2Watchdog implements ISoundTriggerHw2 {
private static final long TIMEOUT_MS = 3000;
private static final String TAG = "SoundTriggerHw2Watchdog";
- private final @NonNull
- ISoundTriggerHw2 mUnderlying;
- private final @NonNull
- Timer mTimer;
+ private final @NonNull ISoundTriggerHw2 mUnderlying;
+ private final @NonNull UptimeTimer mTimer;
public SoundTriggerHw2Watchdog(@NonNull ISoundTriggerHw2 underlying) {
mUnderlying = Objects.requireNonNull(underlying);
- mTimer = new Timer("SoundTriggerHw2Watchdog");
+ mTimer = new UptimeTimer("SoundTriggerHw2Watchdog");
}
@Override
@@ -149,21 +145,16 @@ public class SoundTriggerHw2Watchdog implements ISoundTriggerHw2 {
}
private class Watchdog implements AutoCloseable {
- private final @NonNull
- TimerTask mTask;
+ private final @NonNull UptimeTimer.Task mTask;
// This exception is used merely for capturing a stack trace at the time of creation.
private final @NonNull
Exception mException = new Exception();
Watchdog() {
- mTask = new TimerTask() {
- @Override
- public void run() {
- Log.e(TAG, "HAL deadline expired. Rebooting.", mException);
- rebootHal();
- }
- };
- mTimer.schedule(mTask, TIMEOUT_MS);
+ mTask = mTimer.createTask(() -> {
+ Log.e(TAG, "HAL deadline expired. Rebooting.", mException);
+ rebootHal();
+ }, TIMEOUT_MS);
}
@Override
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/UptimeTimer.java b/services/core/java/com/android/server/soundtrigger_middleware/UptimeTimer.java
new file mode 100644
index 000000000000..bfcc7d840662
--- /dev/null
+++ b/services/core/java/com/android/server/soundtrigger_middleware/UptimeTimer.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2021 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.server.soundtrigger_middleware;
+
+import android.annotation.NonNull;
+import android.os.Handler;
+import android.os.Looper;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * A simple timer, similar to java.util.Timer, but using the "uptime clock".
+ *
+ * Example usage:
+ * UptimeTimer timer = new UptimeTimer("TimerThread");
+ * UptimeTimer.Task task = timer.createTask(() -> { ... }, 100);
+ * ...
+ * // optionally, some time later:
+ * task.cancel();
+ */
+class UptimeTimer {
+ private Handler mHandler = null;
+
+ interface Task {
+ void cancel();
+ }
+
+ UptimeTimer(String threadName) {
+ new Thread(this::threadFunc, threadName).start();
+ synchronized (this) {
+ while (mHandler == null) {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ }
+
+ Task createTask(@NonNull Runnable runnable, long uptimeMs) {
+ TaskImpl task = new TaskImpl(runnable);
+ mHandler.postDelayed(task, uptimeMs);
+ return task;
+ }
+
+ private void threadFunc() {
+ Looper.prepare();
+ synchronized (this) {
+ mHandler = new Handler(Looper.myLooper());
+ notifyAll();
+ }
+ Looper.loop();
+ }
+
+ private static class TaskImpl implements Task, Runnable {
+ private AtomicReference<Runnable> mRunnable = new AtomicReference<>();
+
+ TaskImpl(@NonNull Runnable runnable) {
+ mRunnable.set(runnable);
+ }
+
+ @Override
+ public void cancel() {
+ mRunnable.set(null);
+ }
+
+ @Override
+ public void run() {
+ Runnable runnable = mRunnable.get();
+ if (runnable != null) {
+ runnable.run();
+ }
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/UptimeTimerTest.java b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/UptimeTimerTest.java
new file mode 100644
index 000000000000..38297bf624b7
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/UptimeTimerTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2021 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.server.soundtrigger_middleware;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+@RunWith(AndroidJUnit4.class)
+public class UptimeTimerTest {
+ private static final String TAG = "UptimeTimerTest";
+
+ @Test
+ public void testBasic() throws InterruptedException {
+ AtomicBoolean taskRan = new AtomicBoolean(false);
+ UptimeTimer timer = new UptimeTimer("TestTimer");
+ timer.createTask(() -> taskRan.set(true), 100);
+ Thread.sleep(50);
+ boolean before = taskRan.get();
+ Thread.sleep(100);
+ boolean after = taskRan.get();
+ assertFalse(before);
+ assertTrue(after);
+ }
+
+ @Test
+ public void testCancel() throws InterruptedException {
+ AtomicBoolean taskRan = new AtomicBoolean(false);
+ UptimeTimer timer = new UptimeTimer("TestTimer");
+ UptimeTimer.Task task = timer.createTask(() -> taskRan.set(true), 100);
+ Thread.sleep(50);
+ boolean before = taskRan.get();
+ task.cancel();
+ Thread.sleep(100);
+ boolean after = taskRan.get();
+ assertFalse(before);
+ assertFalse(after);
+ }
+}