1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.soundtrigger_middleware; 18 19 import android.annotation.NonNull; 20 import android.media.soundtrigger.ModelParameterRange; 21 import android.media.soundtrigger.PhraseSoundModel; 22 import android.media.soundtrigger.Properties; 23 import android.media.soundtrigger.RecognitionConfig; 24 import android.media.soundtrigger.SoundModel; 25 import android.os.IBinder; 26 import android.util.Slog; 27 28 import java.util.Objects; 29 30 /** 31 * An {@link ISoundTriggerHal} decorator that would enforce deadlines on all calls and reboot the 32 * HAL whenever they expire. 33 */ 34 public class SoundTriggerHalWatchdog implements ISoundTriggerHal { 35 private static final long TIMEOUT_MS = 3000; 36 private static final String TAG = "SoundTriggerHalWatchdog"; 37 38 private final @NonNull ISoundTriggerHal mUnderlying; 39 private final @NonNull UptimeTimer mTimer; 40 SoundTriggerHalWatchdog(@onNull ISoundTriggerHal underlying)41 public SoundTriggerHalWatchdog(@NonNull ISoundTriggerHal underlying) { 42 mUnderlying = Objects.requireNonNull(underlying); 43 mTimer = new UptimeTimer("SoundTriggerHalWatchdog"); 44 } 45 46 @Override getProperties()47 public Properties getProperties() { 48 try (Watchdog ignore = new Watchdog()) { 49 return mUnderlying.getProperties(); 50 } 51 } 52 53 @Override registerCallback(GlobalCallback callback)54 public void registerCallback(GlobalCallback callback) { 55 try (Watchdog ignore = new Watchdog()) { 56 mUnderlying.registerCallback(callback); 57 } 58 } 59 60 @Override loadSoundModel(SoundModel soundModel, ModelCallback callback)61 public int loadSoundModel(SoundModel soundModel, ModelCallback callback) { 62 try (Watchdog ignore = new Watchdog()) { 63 return mUnderlying.loadSoundModel(soundModel, callback); 64 } 65 } 66 67 @Override loadPhraseSoundModel(PhraseSoundModel soundModel, ModelCallback callback)68 public int loadPhraseSoundModel(PhraseSoundModel soundModel, 69 ModelCallback callback) { 70 try (Watchdog ignore = new Watchdog()) { 71 return mUnderlying.loadPhraseSoundModel(soundModel, callback); 72 } 73 } 74 75 @Override unloadSoundModel(int modelHandle)76 public void unloadSoundModel(int modelHandle) { 77 try (Watchdog ignore = new Watchdog()) { 78 mUnderlying.unloadSoundModel(modelHandle); 79 } 80 } 81 82 @Override stopRecognition(int modelHandle)83 public void stopRecognition(int modelHandle) { 84 try (Watchdog ignore = new Watchdog()) { 85 mUnderlying.stopRecognition(modelHandle); 86 } 87 } 88 89 @Override startRecognition(int modelHandle, int deviceHandle, int ioHandle, RecognitionConfig config)90 public void startRecognition(int modelHandle, int deviceHandle, int ioHandle, 91 RecognitionConfig config) { 92 try (Watchdog ignore = new Watchdog()) { 93 mUnderlying.startRecognition(modelHandle, deviceHandle, ioHandle, config); 94 } 95 } 96 97 @Override forceRecognitionEvent(int modelHandle)98 public void forceRecognitionEvent(int modelHandle) { 99 try (Watchdog ignore = new Watchdog()) { 100 mUnderlying.forceRecognitionEvent(modelHandle); 101 } 102 } 103 104 @Override getModelParameter(int modelHandle, int param)105 public int getModelParameter(int modelHandle, int param) { 106 try (Watchdog ignore = new Watchdog()) { 107 return mUnderlying.getModelParameter(modelHandle, param); 108 } 109 } 110 111 @Override setModelParameter(int modelHandle, int param, int value)112 public void setModelParameter(int modelHandle, int param, int value) { 113 try (Watchdog ignore = new Watchdog()) { 114 mUnderlying.setModelParameter(modelHandle, param, value); 115 } 116 } 117 118 @Override queryParameter(int modelHandle, int param)119 public ModelParameterRange queryParameter(int modelHandle, int param) { 120 try (Watchdog ignore = new Watchdog()) { 121 return mUnderlying.queryParameter(modelHandle, param); 122 } 123 } 124 125 @Override linkToDeath(IBinder.DeathRecipient recipient)126 public void linkToDeath(IBinder.DeathRecipient recipient) { 127 mUnderlying.linkToDeath(recipient); 128 } 129 130 @Override unlinkToDeath(IBinder.DeathRecipient recipient)131 public void unlinkToDeath(IBinder.DeathRecipient recipient) { 132 mUnderlying.unlinkToDeath(recipient); 133 } 134 135 @Override interfaceDescriptor()136 public String interfaceDescriptor() { 137 return mUnderlying.interfaceDescriptor(); 138 } 139 140 @Override flushCallbacks()141 public void flushCallbacks() { 142 mUnderlying.flushCallbacks(); 143 } 144 145 @Override clientAttached(IBinder binder)146 public void clientAttached(IBinder binder) { 147 mUnderlying.clientAttached(binder); 148 } 149 150 @Override clientDetached(IBinder binder)151 public void clientDetached(IBinder binder) { 152 mUnderlying.clientDetached(binder); 153 } 154 155 @Override reboot()156 public void reboot() { 157 mUnderlying.reboot(); 158 } 159 160 @Override detach()161 public void detach() { 162 mUnderlying.detach(); 163 // We should no longer have any pending calls 164 mTimer.quit(); 165 } 166 167 private class Watchdog implements AutoCloseable { 168 private final @NonNull UptimeTimer.Task mTask; 169 // This exception is used merely for capturing a stack trace at the time of creation. 170 private final @NonNull 171 Exception mException = new Exception(); 172 Watchdog()173 Watchdog() { 174 mTask = mTimer.createTask(() -> { 175 Slog.e(TAG, "HAL deadline expired. Rebooting.", mException); 176 reboot(); 177 }, TIMEOUT_MS); 178 } 179 180 @Override close()181 public void close() { 182 mTask.cancel(); 183 } 184 } 185 } 186