Merge "Run sound trigger HAL watchdog on uptime clock"
This commit is contained in:
committed by
Android (Google) Code Review
commit
4d0b9f062b
@@ -26,8 +26,6 @@ import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
/**
|
||||
* An {@link ISoundTriggerHal} decorator that would enforce deadlines on all calls and reboot the
|
||||
@@ -38,11 +36,11 @@ public class SoundTriggerHalWatchdog implements ISoundTriggerHal {
|
||||
private static final String TAG = "SoundTriggerHalWatchdog";
|
||||
|
||||
private final @NonNull ISoundTriggerHal mUnderlying;
|
||||
private final @NonNull Timer mTimer;
|
||||
private final @NonNull UptimeTimer mTimer;
|
||||
|
||||
public SoundTriggerHalWatchdog(@NonNull ISoundTriggerHal underlying) {
|
||||
mUnderlying = Objects.requireNonNull(underlying);
|
||||
mTimer = new Timer("SoundTriggerHalWatchdog");
|
||||
mTimer = new UptimeTimer("SoundTriggerHalWatchdog");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -155,21 +153,16 @@ public class SoundTriggerHalWatchdog implements ISoundTriggerHal {
|
||||
}
|
||||
|
||||
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);
|
||||
reboot();
|
||||
}
|
||||
};
|
||||
mTimer.schedule(mTask, TIMEOUT_MS);
|
||||
mTask = mTimer.createTask(() -> {
|
||||
Log.e(TAG, "HAL deadline expired. Rebooting.", mException);
|
||||
reboot();
|
||||
}, TIMEOUT_MS);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user