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

Commit 1e03bc05 authored by Nicholas Ambur's avatar Nicholas Ambur
Browse files

Crash service on SoundTriger HAL fatal error

Throwing an exception is not enough in this case. When the HAL
behaves unexpectedly, the system service and the HAL must be
reset and the client must be notified. Without a full reset in
this catastrophic case, the state of the HAL and the system service
cannot be guaranteed to the client.

Bug: 150569186
Test: Intentionally load an incompatible voice model and confirm the
device can recover.
Change-Id: Ia7c3f25e48f04bf32a96c64ec998fdfa52459685
parent 571a08fe
Loading
Loading
Loading
Loading
+8 −7
Original line number Diff line number Diff line
@@ -780,15 +780,16 @@ public class AlwaysOnHotwordDetector {
            audioCapabilities |= AUDIO_CAPABILITY_NOISE_SUPPRESSION;
        }

        int code = STATUS_ERROR;
        int code;
        try {
            code = mModelManagementService.startRecognition(
                    mKeyphraseMetadata.id, mLocale.toLanguageTag(), mInternalCallback,
                    new RecognitionConfig(captureTriggerAudio, allowMultipleTriggers,
                            recognitionExtra, null /* additional data */, audioCapabilities));
        } catch (RemoteException e) {
            Slog.w(TAG, "RemoteException in startRecognition!", e);
            throw e.rethrowFromSystemServer();
        }

        if (code != STATUS_OK) {
            Slog.w(TAG, "startRecognition() failed with error code " + code);
        }
@@ -796,12 +797,12 @@ public class AlwaysOnHotwordDetector {
    }

    private int stopRecognitionLocked() {
        int code = STATUS_ERROR;
        int code;
        try {
            code = mModelManagementService.stopRecognition(mKeyphraseMetadata.id,
                    mInternalCallback);
        } catch (RemoteException e) {
            Slog.w(TAG, "RemoteException in stopRecognition!", e);
            throw e.rethrowFromSystemServer();
        }

        if (code != STATUS_OK) {
@@ -968,12 +969,12 @@ public class AlwaysOnHotwordDetector {
                }
            }

            ModuleProperties dspModuleProperties = null;
            ModuleProperties dspModuleProperties;
            try {
                dspModuleProperties =
                        mModelManagementService.getDspModuleProperties();
            } catch (RemoteException e) {
                Slog.w(TAG, "RemoteException in getDspProperties!", e);
                throw e.rethrowFromSystemServer();
            }

            // No DSP available
@@ -989,7 +990,7 @@ public class AlwaysOnHotwordDetector {
                mKeyphraseMetadata = mModelManagementService.getEnrolledKeyphraseMetadata(
                        mText, mLocale.toLanguageTag());
            } catch (RemoteException e) {
                Slog.w(TAG, "RemoteException in internalUpdateEnrolledKeyphraseMetadata", e);
                throw e.rethrowFromSystemServer();
            }
        }
    }
+34 −9
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.Settings;
import android.util.ArraySet;
import android.util.Log;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IVoiceActionCheckCallback;
@@ -47,6 +48,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Set;

/**
@@ -63,6 +65,8 @@ import java.util.Set;
 * separate process from this one.
 */
public class VoiceInteractionService extends Service {
    static final String TAG = VoiceInteractionService.class.getSimpleName();

    /**
     * The {@link Intent} that must be declared as handled by the service.
     * To be supported, the service must also require the
@@ -240,9 +244,22 @@ public class VoiceInteractionService extends Service {
    public void onReady() {
        mSystemService = IVoiceInteractionManagerService.Stub.asInterface(
                ServiceManager.getService(Context.VOICE_INTERACTION_MANAGER_SERVICE));
        Objects.requireNonNull(mSystemService);
        try {
            mSystemService.asBinder().linkToDeath(mDeathRecipient, 0);
        } catch (RemoteException e) {
            Log.wtf(TAG, "unable to link to death with system service");
        }
        mKeyphraseEnrollmentInfo = new KeyphraseEnrollmentInfo(getPackageManager());
    }

    private IBinder.DeathRecipient mDeathRecipient = () -> {
        Log.e(TAG, "system service binder died shutting down");
        Handler.getMain().executeOrSendMessage(PooledLambda.obtainMessage(
                VoiceInteractionService::onShutdownInternal, VoiceInteractionService.this));
    };


    private void onShutdownInternal() {
        onShutdown();
        // Stop any active recognitions when shutting down.
@@ -349,17 +366,25 @@ public class VoiceInteractionService extends Service {
    }

    private void safelyShutdownHotwordDetector() {
        try {
        synchronized (mLock) {
                if (mHotwordDetector != null) {
                    mHotwordDetector.stopRecognition();
                    mHotwordDetector.invalidate();
                    mHotwordDetector = null;
            if (mHotwordDetector == null) {
                return;
            }

            try {
                mHotwordDetector.stopRecognition();
            } catch (Exception ex) {
                // Ignore.
            }

            try {
                mHotwordDetector.invalidate();
            } catch (Exception ex) {
                // Ignore.
            }

            mHotwordDetector = null;
        }
    }

    /**
+9 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import android.media.soundtrigger_middleware.SoundModel;
import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
import android.media.soundtrigger_middleware.Status;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.util.Log;
@@ -139,6 +140,14 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware
            throw new ServiceSpecificException(((RecoverableException) e).errorCode,
                    e.getMessage());
        }

        /* Throwing an exception is not enough in this case. When the HAL behaves unexpectedly, the
           system service and the HAL must be reset and the client must be notified. Without a full
           reset in this catastrophic case, the state of the HAL and the system service cannot be
           guaranteed to the client.
         */
        Log.wtf(TAG, "Crashing system server due to unrecoverable exception", e);
        Process.killProcess(Process.myPid());
        throw new InternalServerError(e);
    }