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

Commit 14de6500 authored by Atneya Nair's avatar Atneya Nair
Browse files

Protect STHelper from calls after detach

Now that we expose detach to upper layers, we should ensure that
calling a method on a detached STHelper strongly errors.

Fixes: 277390523
Bug: 272147641
Test: atest AlwaysOnHotwordDetectorTest#isSessionInvalid_afterDetach
Change-Id: I32cf30d711e27debed0d643a9627663830e2ccf6
parent d05c02ef
Loading
Loading
Loading
Loading
+70 −24
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Slog;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.MetricsLogger;

import java.io.FileDescriptor;
@@ -129,6 +130,9 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
    private final Function<SoundTrigger.StatusListener, SoundTriggerModule> mModuleProvider;
    private final Supplier<List<ModuleProperties>> mModulePropertiesProvider;

    @GuardedBy("mLock")
    private boolean mIsDetached = false;

    SoundTriggerHelper(Context context,
            @NonNull Function<SoundTrigger.StatusListener, SoundTriggerModule> moduleProvider,
            int moduleId,
@@ -184,7 +188,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
     * recognition.
     * @return One of {@link #STATUS_ERROR} or {@link #STATUS_OK}.
     */
    int startGenericRecognition(UUID modelId, GenericSoundModel soundModel,
    public int startGenericRecognition(UUID modelId, GenericSoundModel soundModel,
            IRecognitionStatusCallback callback, RecognitionConfig recognitionConfig,
            boolean runInBatterySaverMode) {
        MetricsLogger.count(mContext, "sth_start_recognition", 1);
@@ -195,6 +199,9 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
        }

        synchronized (mLock) {
            if (mIsDetached) {
                throw new IllegalStateException("SoundTriggerHelper has been detached");
            }
            ModelData modelData = getOrCreateGenericModelDataLocked(modelId);
            if (modelData == null) {
                Slog.w(TAG, "Irrecoverable error occurred, check UUID / sound model data.");
@@ -214,7 +221,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
     * @param callback The callback for the recognition events related to the given keyphrase.
     * @return One of {@link #STATUS_ERROR} or {@link #STATUS_OK}.
     */
    int startKeyphraseRecognition(int keyphraseId, KeyphraseSoundModel soundModel,
    public int startKeyphraseRecognition(int keyphraseId, KeyphraseSoundModel soundModel,
            IRecognitionStatusCallback callback, RecognitionConfig recognitionConfig,
            boolean runInBatterySaverMode) {
        synchronized (mLock) {
@@ -223,6 +230,10 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
                return STATUS_ERROR;
            }

            if (mIsDetached) {
                throw new IllegalStateException("SoundTriggerHelper has been detached");
            }

            if (DBG) {
                Slog.d(TAG, "startKeyphraseRecognition for keyphraseId=" + keyphraseId
                        + " soundModel=" + soundModel + ", callback=" + callback.asBinder()
@@ -311,7 +322,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
     * for the recognition.
     * @return One of {@link #STATUS_ERROR} or {@link #STATUS_OK}.
     */
    int startRecognition(SoundModel soundModel, ModelData modelData,
    private int startRecognition(SoundModel soundModel, ModelData modelData,
            IRecognitionStatusCallback callback, RecognitionConfig recognitionConfig,
            int keyphraseId, boolean runInBatterySaverMode) {
        synchronized (mLock) {
@@ -385,7 +396,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
     *
     * @return One of {@link #STATUS_ERROR} or {@link #STATUS_OK}.
     */
    int stopGenericRecognition(UUID modelId, IRecognitionStatusCallback callback) {
    public int stopGenericRecognition(UUID modelId, IRecognitionStatusCallback callback) {
        synchronized (mLock) {
            MetricsLogger.count(mContext, "sth_stop_recognition", 1);
            if (callback == null || modelId == null) {
@@ -393,7 +404,9 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
                        modelId);
                return STATUS_ERROR;
            }

            if (mIsDetached) {
                throw new IllegalStateException("SoundTriggerHelper has been detached");
            }
            ModelData modelData = mModelDataMap.get(modelId);
            if (modelData == null || !modelData.isGenericModel()) {
                Slog.w(TAG, "Attempting stopRecognition on invalid model with id:" + modelId);
@@ -418,7 +431,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
     *
     * @return One of {@link #STATUS_ERROR} or {@link #STATUS_OK}.
     */
    int stopKeyphraseRecognition(int keyphraseId, IRecognitionStatusCallback callback) {
    public int stopKeyphraseRecognition(int keyphraseId, IRecognitionStatusCallback callback) {
        synchronized (mLock) {
            MetricsLogger.count(mContext, "sth_stop_recognition", 1);
            if (callback == null) {
@@ -426,7 +439,9 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
                        keyphraseId);
                return STATUS_ERROR;
            }

            if (mIsDetached) {
                throw new IllegalStateException("SoundTriggerHelper has been detached");
            }
            ModelData modelData = getKeyphraseModelDataLocked(keyphraseId);
            if (modelData == null || !modelData.isKeyphraseModel()) {
                Slog.w(TAG, "No model exists for given keyphrase Id " + keyphraseId);
@@ -538,6 +553,11 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
    }

    public ModuleProperties getModuleProperties() {
        synchronized (mLock) {
            if (mIsDetached) {
                throw new IllegalStateException("SoundTriggerHelper has been detached");
            }
        }
        for (ModuleProperties moduleProperties : mModulePropertiesProvider.get()) {
            if (moduleProperties.getId() == mModuleId) {
                return moduleProperties;
@@ -547,7 +567,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
        return null;
    }

    int unloadKeyphraseSoundModel(int keyphraseId) {
    public int unloadKeyphraseSoundModel(int keyphraseId) {
        synchronized (mLock) {
            MetricsLogger.count(mContext, "sth_unload_keyphrase_sound_model", 1);
            ModelData modelData = getKeyphraseModelDataLocked(keyphraseId);
@@ -555,7 +575,9 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
                    || !modelData.isKeyphraseModel()) {
                return STATUS_ERROR;
            }

            if (mIsDetached) {
                throw new IllegalStateException("SoundTriggerHelper has been detached");
            }
            // Stop recognition if it's the current one.
            modelData.setRequested(false);
            int status = updateRecognitionLocked(modelData, false);
@@ -574,12 +596,15 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
        }
    }

    int unloadGenericSoundModel(UUID modelId) {
    public int unloadGenericSoundModel(UUID modelId) {
        synchronized (mLock) {
            MetricsLogger.count(mContext, "sth_unload_generic_sound_model", 1);
            if (modelId == null || mModule == null) {
                return STATUS_ERROR;
            }
            if (mIsDetached) {
                throw new IllegalStateException("SoundTriggerHelper has been detached");
            }
            ModelData modelData = mModelDataMap.get(modelId);
            if (modelData == null || !modelData.isGenericModel()) {
                Slog.w(TAG, "Unload error: Attempting unload invalid generic model with id:" +
@@ -615,19 +640,25 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
        }
    }

    boolean isRecognitionRequested(UUID modelId) {
    public boolean isRecognitionRequested(UUID modelId) {
        synchronized (mLock) {
            if (mIsDetached) {
                throw new IllegalStateException("SoundTriggerHelper has been detached");
            }
            ModelData modelData = mModelDataMap.get(modelId);
            return modelData != null && modelData.isRequested();
        }
    }

    int getGenericModelState(UUID modelId) {
    public int getGenericModelState(UUID modelId) {
        synchronized (mLock) {
            MetricsLogger.count(mContext, "sth_get_generic_model_state", 1);
            if (modelId == null || mModule == null) {
                return STATUS_ERROR;
            }
            if (mIsDetached) {
                throw new IllegalStateException("SoundTriggerHelper has been detached");
            }
            ModelData modelData = mModelDataMap.get(modelId);
            if (modelData == null || !modelData.isGenericModel()) {
                Slog.w(TAG, "GetGenericModelState error: Invalid generic model id:" +
@@ -647,19 +678,20 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
        }
    }

    int getKeyphraseModelState(UUID modelId) {
        Slog.w(TAG, "GetKeyphraseModelState error: Not implemented");
        return STATUS_ERROR;
    }

    int setParameter(UUID modelId, @ModelParams int modelParam, int value) {
    public int setParameter(UUID modelId, @ModelParams int modelParam, int value) {
        synchronized (mLock) {
            if (mIsDetached) {
                throw new IllegalStateException("SoundTriggerHelper has been detached");
            }
            return setParameterLocked(mModelDataMap.get(modelId), modelParam, value);
        }
    }

    int setKeyphraseParameter(int keyphraseId, @ModelParams int modelParam, int value) {
    public int setKeyphraseParameter(int keyphraseId, @ModelParams int modelParam, int value) {
        synchronized (mLock) {
            if (mIsDetached) {
                throw new IllegalStateException("SoundTriggerHelper has been detached");
            }
            return setParameterLocked(getKeyphraseModelDataLocked(keyphraseId), modelParam, value);
        }
    }
@@ -678,14 +710,20 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
        return mModule.setParameter(modelData.getHandle(), modelParam, value);
    }

    int getParameter(@NonNull UUID modelId, @ModelParams int modelParam) {
    public int getParameter(@NonNull UUID modelId, @ModelParams int modelParam) {
        synchronized (mLock) {
            if (mIsDetached) {
                throw new IllegalStateException("SoundTriggerHelper has been detached");
            }
            return getParameterLocked(mModelDataMap.get(modelId), modelParam);
        }
    }

    int getKeyphraseParameter(int keyphraseId, @ModelParams int modelParam) {
    public int getKeyphraseParameter(int keyphraseId, @ModelParams int modelParam) {
        synchronized (mLock) {
            if (mIsDetached) {
                throw new IllegalStateException("SoundTriggerHelper has been detached");
            }
            return getParameterLocked(getKeyphraseModelDataLocked(keyphraseId), modelParam);
        }
    }
@@ -707,15 +745,21 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
    }

    @Nullable
    ModelParamRange queryParameter(@NonNull UUID modelId, @ModelParams int modelParam) {
    public ModelParamRange queryParameter(@NonNull UUID modelId, @ModelParams int modelParam) {
        synchronized (mLock) {
            if (mIsDetached) {
                throw new IllegalStateException("SoundTriggerHelper has been detached");
            }
            return queryParameterLocked(mModelDataMap.get(modelId), modelParam);
        }
    }

    @Nullable
    ModelParamRange queryKeyphraseParameter(int keyphraseId, @ModelParams int modelParam) {
    public ModelParamRange queryKeyphraseParameter(int keyphraseId, @ModelParams int modelParam) {
        synchronized (mLock) {
            if (mIsDetached) {
                throw new IllegalStateException("SoundTriggerHelper has been detached");
            }
            return queryParameterLocked(getKeyphraseModelDataLocked(keyphraseId), modelParam);
        }
    }
@@ -1115,12 +1159,14 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
     */
    public void detach() {
        synchronized (mLock) {
            if (mIsDetached) return;
            for (ModelData model : mModelDataMap.values()) {
                forceStopAndUnloadModelLocked(model, null);
            }
            mModelDataMap.clear();
            internalClearGlobalStateLocked();
            if (mModule != null) {
                mIsDetached = true;
                mModule.detach();
                mModule = null;
            }
@@ -1289,7 +1335,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
     * @param modelData Model data to be used for recognition
     * @return True if device state allows recognition to run, false if not.
     */
    boolean isRecognitionAllowedByPowerState(ModelData modelData) {
    private boolean isRecognitionAllowedByPowerState(ModelData modelData) {
        return mSoundTriggerPowerSaveMode == PowerManager.SOUND_TRIGGER_MODE_ALL_ENABLED
                || (mSoundTriggerPowerSaveMode == PowerManager.SOUND_TRIGGER_MODE_CRITICAL_ONLY
                && modelData.shouldRunInBatterySaverMode());