Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4b5f06df authored by Ytai Ben-tsvi's avatar Ytai Ben-tsvi Committed by Android (Google) Code Review
Browse files

Merge "Explicitly close sound model file descriptors" into tm-dev

parents 0a1eeefb 8dc40270
Loading
Loading
Loading
Loading
+30 −2
Original line number Diff line number Diff line
@@ -37,6 +37,8 @@ import android.os.Message;
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 @@ public class SoundTriggerModule {
            if (model instanceof SoundTrigger.GenericSoundModel) {
                SoundModel aidlModel = ConversionUtil.api2aidlGenericSoundModel(
                        (SoundTrigger.GenericSoundModel) model);
                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);
                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;
+24 −0
Original line number Diff line number Diff line
@@ -29,7 +29,9 @@ import android.os.IBinder;
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 @@ import java.util.concurrent.atomic.AtomicReference;
 * </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 @@ final class SoundTriggerHw2Compat implements ISoundTriggerHal {
            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 @@ final class SoundTriggerHw2Compat implements ISoundTriggerHal {
            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);
                }
            }
        }
    }

+15 −14
Original line number Diff line number Diff line
@@ -31,7 +31,6 @@ import static org.mockito.Mockito.atMost;
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.IBinder;
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 org.mockito.ArgumentCaptor;

import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

@RunWith(Parameterized.class)
public class SoundHw2CompatTest {
@@ -240,14 +239,15 @@ public class SoundHw2CompatTest {
                (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 @@ public class SoundHw2CompatTest {
        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 @@ public class SoundHw2CompatTest {
                (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 @@ public class SoundHw2CompatTest {
        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;
    }
+42 −27
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ import android.os.HidlMemoryUtil;
import android.os.ParcelFileDescriptor;
import android.os.SharedMemory;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.List;

@@ -82,6 +83,19 @@ class TestUtil {
                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 @@ class TestUtil {
        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 @@ class TestUtil {
        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 @@ class TestUtil {
        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 @@ class TestUtil {
        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 @@ class TestUtil {
            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 @@ class TestUtil {
        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 @@ class TestUtil {
        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 @@ class TestUtil {
        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);