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

Commit 3559e869 authored by Ytai Ben-Tsvi's avatar Ytai Ben-Tsvi
Browse files

Clean up on client death in SoundTriggerService

This change adds tracking of SoundTriggerService client death
and frees up resources whenever that happens.

Test: Kill Now Playing process and observer recovery.
Bug: 171026874
Change-Id: Ie31d0a3ed392b1513b4e81ec3c344f4e79adcf52
parent 41627475
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -40,7 +40,9 @@ import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
import android.media.AudioFormat;
import android.media.permission.Identity;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.util.Slog;
@@ -246,6 +248,7 @@ public class AlwaysOnHotwordDetector {
    private final Callback mExternalCallback;
    private final Object mLock = new Object();
    private final Handler mHandler;
    private final IBinder mBinder = new Binder();

    private int mAvailability = STATE_NOT_READY;

@@ -450,7 +453,7 @@ public class AlwaysOnHotwordDetector {
            Identity identity = new Identity();
            identity.packageName = ActivityThread.currentOpPackageName();
            mSoundTriggerSession = mModelManagementService.createSoundTriggerSessionAsOriginator(
                    identity);
                    identity, mBinder);
        } catch (RemoteException e) {
            throw e.rethrowAsRuntimeException();
        }
+10 −2
Original line number Diff line number Diff line
@@ -38,8 +38,12 @@ interface ISoundTriggerService {
     *
     * It is good practice to clear the binder calling identity prior to calling this, in case the
     * caller is ever in the same process as the callee.
     *
     * The binder object being passed is used by the server to keep track of client death, in order
     * to clean-up whenever that happens.
     */
    ISoundTriggerSession attachAsOriginator(in Identity originatorIdentity);
    ISoundTriggerSession attachAsOriginator(in Identity originatorIdentity,
                                            IBinder client);

    /**
     * Creates a new session.
@@ -54,7 +58,11 @@ interface ISoundTriggerService {
     *
     * It is good practice to clear the binder calling identity prior to calling this, in case the
     * caller is ever in the same process as the callee.
     *
     * The binder object being passed is used by the server to keep track of client death, in order
     * to clean-up whenever that happens.
     */
    ISoundTriggerSession attachAsMiddleman(in Identity middlemanIdentity,
                                           in Identity originatorIdentity);
                                           in Identity originatorIdentity,
                                           IBinder client);
}
+5 −1
Original line number Diff line number Diff line
@@ -216,7 +216,11 @@ interface IVoiceInteractionManagerService {
     * Caller must provide an identity, used for permission tracking purposes.
     * The uid/pid elements of the identity will be ignored by the server and replaced with the ones
     * provided by binder.
     *
     * The client argument is any binder owned by the client, used for tracking is death and
     * cleaning up in this event.
     */
    IVoiceInteractionSoundTriggerSession createSoundTriggerSessionAsOriginator(
            in Identity originatorIdentity);
            in Identity originatorIdentity,
            IBinder client);
}
+4 −1
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.ParcelUuid;
import android.os.RemoteException;
import android.provider.Settings;
@@ -69,6 +70,7 @@ public final class SoundTriggerManager {

    private final Context mContext;
    private final ISoundTriggerSession mSoundTriggerSession;
    private final IBinder mBinderToken = new Binder();

    // Stores a mapping from the sound model UUID to the SoundTriggerInstance created by
    // the createSoundTriggerDetector() call.
@@ -90,7 +92,8 @@ public final class SoundTriggerManager {
            originatorIdentity.packageName = ActivityThread.currentOpPackageName();

            try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
                mSoundTriggerSession = soundTriggerService.attachAsOriginator(originatorIdentity);
                mSoundTriggerSession = soundTriggerService.attachAsOriginator(originatorIdentity,
                        mBinderToken);
            }
        } catch (RemoteException e) {
            throw e.rethrowAsRuntimeException();
+20 −1
Original line number Diff line number Diff line
@@ -1139,6 +1139,25 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
        }
    }

    /**
     * Stops and unloads all models. This is intended as a clean-up call with the expectation that
     * this instance is not used after.
     * @hide
     */
    public void detach() {
        synchronized (mLock) {
            for (ModelData model : mModelDataMap.values()) {
                forceStopAndUnloadModelLocked(model, null);
            }
            mModelDataMap.clear();
            internalClearGlobalStateLocked();
            if (mModule != null) {
                mModule.detach();
                mModule = null;
            }
        }
    }

    /**
     * Stops and unloads a sound model, and removes any reference to the model if successful.
     *
@@ -1170,7 +1189,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
        }
        if (modelData.isModelStarted()) {
            Slog.d(TAG, "Stopping previously started dangling model " + modelData.getHandle());
            if (mModule.stopRecognition(modelData.getHandle()) != STATUS_OK) {
            if (mModule.stopRecognition(modelData.getHandle()) == STATUS_OK) {
                modelData.setStopped();
                modelData.setRequested(false);
            } else {
Loading