Merge "Explicitly close sound model file descriptors" into tm-dev
diff --git a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
index bf4b514..eed92c1 100644
--- a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
+++ b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
@@ -37,6 +37,8 @@
import android.os.RemoteException;
import android.util.Log;
+import java.io.IOException;
+
/**
* The SoundTriggerModule provides APIs to control sound models and sound detection
* on a given sound trigger hardware module.
@@ -137,13 +139,39 @@
if (model instanceof SoundTrigger.GenericSoundModel) {
SoundModel aidlModel = ConversionUtil.api2aidlGenericSoundModel(
(SoundTrigger.GenericSoundModel) model);
- soundModelHandle[0] = mService.loadModel(aidlModel);
+ try {
+ soundModelHandle[0] = mService.loadModel(aidlModel);
+ } finally {
+ // TODO(b/219825762): We should be able to use the entire object in a
+ // try-with-resources
+ // clause, instead of having to explicitly close internal fields.
+ if (aidlModel.data != null) {
+ try {
+ aidlModel.data.close();
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to close file", e);
+ }
+ }
+ }
return SoundTrigger.STATUS_OK;
}
if (model instanceof SoundTrigger.KeyphraseSoundModel) {
PhraseSoundModel aidlModel = ConversionUtil.api2aidlPhraseSoundModel(
(SoundTrigger.KeyphraseSoundModel) model);
- soundModelHandle[0] = mService.loadPhraseModel(aidlModel);
+ try {
+ soundModelHandle[0] = mService.loadPhraseModel(aidlModel);
+ } finally {
+ // TODO(b/219825762): We should be able to use the entire object in a
+ // try-with-resources
+ // clause, instead of having to explicitly close internal fields.
+ if (aidlModel.common.data != null) {
+ try {
+ aidlModel.common.data.close();
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to close file", e);
+ }
+ }
+ }
return SoundTrigger.STATUS_OK;
}
return SoundTrigger.STATUS_BAD_VALUE;
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java
index c638201..9bbae4b 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java
@@ -29,7 +29,9 @@
import android.os.IHwBinder;
import android.os.RemoteException;
import android.system.OsConstants;
+import android.util.Log;
+import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@@ -54,6 +56,8 @@
* </ul>
*/
final class SoundTriggerHw2Compat implements ISoundTriggerHal {
+ private static final String TAG = "SoundTriggerHw2Compat";
+
private final @NonNull Runnable mRebootRunnable;
private final @NonNull IHwBinder mBinder;
private @NonNull android.hardware.soundtrigger.V2_0.ISoundTriggerHw mUnderlying_2_0;
@@ -226,6 +230,16 @@
return handle.get();
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
+ } finally {
+ // TODO(b/219825762): We should be able to use the entire object in a try-with-resources
+ // clause, instead of having to explicitly close internal fields.
+ if (hidlModel.data != null) {
+ try {
+ hidlModel.data.close();
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to close file", e);
+ }
+ }
}
}
@@ -252,6 +266,16 @@
return handle.get();
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
+ } finally {
+ // TODO(b/219825762): We should be able to use the entire object in a try-with-resources
+ // clause, instead of having to explicitly close internal fields.
+ if (hidlModel.common.data != null) {
+ try {
+ hidlModel.common.data.close();
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to close file", e);
+ }
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java
index 16cfd13..6bdd88c 100644
--- a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java
+++ b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java
@@ -31,7 +31,6 @@
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -49,7 +48,6 @@
import android.os.IHwBinder;
import android.os.IHwInterface;
import android.os.RemoteException;
-import android.system.OsConstants;
import org.junit.After;
import org.junit.Before;
@@ -60,6 +58,7 @@
import java.util.LinkedList;
import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
@RunWith(Parameterized.class)
public class SoundHw2CompatTest {
@@ -240,14 +239,15 @@
(android.hardware.soundtrigger.V2_1.ISoundTriggerHw) mHalDriver;
final int handle = 29;
- ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel> modelCaptor =
- ArgumentCaptor.forClass(
- android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel.class);
+ AtomicReference<android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel> model =
+ new AtomicReference<>();
ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback> callbackCaptor =
ArgumentCaptor.forClass(
android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.class);
doAnswer(invocation -> {
+ // We need to dup the model, as it gets invalidated after the call returns.
+ model.set(TestUtil.dupModel_2_1(invocation.getArgument(0)));
android.hardware.soundtrigger.V2_1.ISoundTriggerHw.loadSoundModel_2_1Callback
resultCallback = invocation.getArgument(3);
@@ -259,10 +259,9 @@
assertEquals(handle,
mCanonical.loadSoundModel(TestUtil.createGenericSoundModel(), canonicalCallback));
- verify(driver_2_1).loadSoundModel_2_1(modelCaptor.capture(), callbackCaptor.capture(),
- anyInt(), any());
+ verify(driver_2_1).loadSoundModel_2_1(any(), callbackCaptor.capture(), anyInt(), any());
- TestUtil.validateGenericSoundModel_2_1(modelCaptor.getValue());
+ TestUtil.validateGenericSoundModel_2_1(model.get());
validateCallback_2_1(callbackCaptor.getValue(), canonicalCallback);
return handle;
}
@@ -355,14 +354,16 @@
(android.hardware.soundtrigger.V2_1.ISoundTriggerHw) mHalDriver;
final int handle = 29;
- ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel>
- modelCaptor = ArgumentCaptor.forClass(
- android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel.class);
+ AtomicReference<android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel> model =
+ new AtomicReference<>();
ArgumentCaptor<android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback> callbackCaptor =
ArgumentCaptor.forClass(
android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.class);
doAnswer(invocation -> {
+ // We need to dup the model, as it gets invalidated after the call returns.
+ model.set(TestUtil.dupPhraseModel_2_1(invocation.getArgument(0)));
+
android.hardware.soundtrigger.V2_1.ISoundTriggerHw.loadPhraseSoundModel_2_1Callback
resultCallback = invocation.getArgument(3);
@@ -374,10 +375,10 @@
assertEquals(handle, mCanonical.loadPhraseSoundModel(TestUtil.createPhraseSoundModel(),
canonicalCallback));
- verify(driver_2_1).loadPhraseSoundModel_2_1(modelCaptor.capture(), callbackCaptor.capture(),
- anyInt(), any());
+ verify(driver_2_1).loadPhraseSoundModel_2_1(any(), callbackCaptor.capture(), anyInt(),
+ any());
- TestUtil.validatePhraseSoundModel_2_1(modelCaptor.getValue());
+ TestUtil.validatePhraseSoundModel_2_1(model.get());
validateCallback_2_1(callbackCaptor.getValue(), canonicalCallback);
return handle;
}
diff --git a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/TestUtil.java b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/TestUtil.java
index e687a2a..30b4a59 100644
--- a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/TestUtil.java
+++ b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/TestUtil.java
@@ -47,6 +47,7 @@
import android.os.ParcelFileDescriptor;
import android.os.SharedMemory;
+import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.List;
@@ -82,6 +83,19 @@
HidlMemoryUtil.hidlMemoryToByteArray(model.data));
}
+ static android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel dupModel_2_1(
+ android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel model) {
+ android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel dup =
+ new android.hardware.soundtrigger.V2_1.ISoundTriggerHw.SoundModel();
+ dup.header = model.header;
+ try {
+ dup.data = model.data.dup();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ return dup;
+ }
+
private static void validateSoundModel_2_0(
android.hardware.soundtrigger.V2_0.ISoundTriggerHw.SoundModel model, int type) {
assertEquals(type, model.type);
@@ -121,6 +135,15 @@
validatePhrases_2_0(model.phrases);
}
+ static android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel dupPhraseModel_2_1(
+ android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel model) {
+ android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel dup =
+ new android.hardware.soundtrigger.V2_1.ISoundTriggerHw.PhraseSoundModel();
+ dup.common = dupModel_2_1(model.common);
+ dup.phrases = model.phrases;
+ return dup;
+ }
+
static void validatePhraseSoundModel_2_0(
android.hardware.soundtrigger.V2_0.ISoundTriggerHw.PhraseSoundModel model) {
validateSoundModel_2_0(model.common,
@@ -190,31 +213,27 @@
properties.maxKeyPhrases = 567;
properties.maxUsers = 678;
properties.recognitionModes =
- RecognitionMode.VOICE_TRIGGER
- | RecognitionMode.USER_IDENTIFICATION
- | RecognitionMode.USER_AUTHENTICATION
- | RecognitionMode.GENERIC_TRIGGER;
+ RecognitionMode.VOICE_TRIGGER | RecognitionMode.USER_IDENTIFICATION
+ | RecognitionMode.USER_AUTHENTICATION | RecognitionMode.GENERIC_TRIGGER;
properties.captureTransition = true;
properties.maxBufferMs = 321;
properties.concurrentCapture = supportConcurrentCapture;
properties.triggerInEvent = true;
properties.powerConsumptionMw = 432;
properties.supportedModelArch = "supportedModelArch";
- properties.audioCapabilities = AudioCapabilities.ECHO_CANCELLATION
- | AudioCapabilities.NOISE_SUPPRESSION;
+ properties.audioCapabilities =
+ AudioCapabilities.ECHO_CANCELLATION | AudioCapabilities.NOISE_SUPPRESSION;
return properties;
}
- static void validateDefaultProperties(Properties properties,
- boolean supportConcurrentCapture) {
+ static void validateDefaultProperties(Properties properties, boolean supportConcurrentCapture) {
validateDefaultProperties(properties, supportConcurrentCapture,
AudioCapabilities.ECHO_CANCELLATION | AudioCapabilities.NOISE_SUPPRESSION,
"supportedModelArch");
}
- static void validateDefaultProperties(Properties properties,
- boolean supportConcurrentCapture, @AudioCapabilities int audioCapabilities,
- @NonNull String supportedModelArch) {
+ static void validateDefaultProperties(Properties properties, boolean supportConcurrentCapture,
+ @AudioCapabilities int audioCapabilities, @NonNull String supportedModelArch) {
assertEquals("implementor", properties.implementor);
assertEquals("description", properties.description);
assertEquals(123, properties.version);
@@ -222,10 +241,9 @@
assertEquals(456, properties.maxSoundModels);
assertEquals(567, properties.maxKeyPhrases);
assertEquals(678, properties.maxUsers);
- assertEquals(RecognitionMode.GENERIC_TRIGGER
- | RecognitionMode.USER_AUTHENTICATION
- | RecognitionMode.USER_IDENTIFICATION
- | RecognitionMode.VOICE_TRIGGER, properties.recognitionModes);
+ assertEquals(RecognitionMode.GENERIC_TRIGGER | RecognitionMode.USER_AUTHENTICATION
+ | RecognitionMode.USER_IDENTIFICATION | RecognitionMode.VOICE_TRIGGER,
+ properties.recognitionModes);
assertTrue(properties.captureTransition);
assertEquals(321, properties.maxBufferMs);
assertEquals(supportConcurrentCapture, properties.concurrentCapture);
@@ -246,8 +264,8 @@
config.phraseRecognitionExtras[0].levels[0].userId = 234;
config.phraseRecognitionExtras[0].levels[0].levelPercent = 34;
config.data = new byte[]{5, 4, 3, 2, 1};
- config.audioCapabilities = AudioCapabilities.ECHO_CANCELLATION
- | AudioCapabilities.NOISE_SUPPRESSION;
+ config.audioCapabilities =
+ AudioCapabilities.ECHO_CANCELLATION | AudioCapabilities.NOISE_SUPPRESSION;
return config;
}
@@ -295,13 +313,12 @@
int captureHandle) {
validateRecognitionConfig_2_1(config.base, captureDevice, captureHandle);
- assertEquals(AudioCapabilities.ECHO_CANCELLATION
- | AudioCapabilities.NOISE_SUPPRESSION, config.audioCapabilities);
+ assertEquals(AudioCapabilities.ECHO_CANCELLATION | AudioCapabilities.NOISE_SUPPRESSION,
+ config.audioCapabilities);
}
static android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionEvent createRecognitionEvent_2_0(
- int hwHandle,
- int status) {
+ int hwHandle, int status) {
android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionEvent halEvent =
new android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionEvent();
halEvent.status = status;
@@ -351,8 +368,7 @@
return event;
}
- static ISoundTriggerHwCallback.RecognitionEvent createRecognitionEvent_2_1(
- int hwHandle,
+ static ISoundTriggerHwCallback.RecognitionEvent createRecognitionEvent_2_1(int hwHandle,
int status) {
ISoundTriggerHwCallback.RecognitionEvent halEvent =
new ISoundTriggerHwCallback.RecognitionEvent();
@@ -386,8 +402,7 @@
PhraseRecognitionExtra extra = new PhraseRecognitionExtra();
extra.id = 123;
extra.confidenceLevel = 52;
- extra.recognitionModes = RecognitionMode.VOICE_TRIGGER
- | RecognitionMode.GENERIC_TRIGGER;
+ extra.recognitionModes = RecognitionMode.VOICE_TRIGGER | RecognitionMode.GENERIC_TRIGGER;
ConfidenceLevel level = new ConfidenceLevel();
level.userId = 31;
level.levelPercent = 43;
@@ -396,8 +411,8 @@
return event;
}
- static android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.PhraseRecognitionEvent
- createPhraseRecognitionEvent_2_0(int hwHandle, int status) {
+ static android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.PhraseRecognitionEvent createPhraseRecognitionEvent_2_0(
+ int hwHandle, int status) {
android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.PhraseRecognitionEvent halEvent =
new android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.PhraseRecognitionEvent();
halEvent.common = createRecognitionEvent_2_0(hwHandle, status);