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

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

Sessionize the SoundTriggerService layer.

This changes associates identity information with every
SoundTrigerService session.

Change-Id: I30c9177f21203c8f3d03d4ff31523137497e760b
Bug: 163865561
parent 0e2f629e
Loading
Loading
Loading
Loading
+35 −43
Original line number Diff line number Diff line
@@ -16,53 +16,45 @@

package com.android.internal.app;

import android.app.PendingIntent;
import android.content.ComponentName;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
import android.hardware.soundtrigger.SoundTrigger;
import android.hardware.soundtrigger.ModelParams;
import android.os.Bundle;
import android.os.ParcelUuid;
import android.media.permission.Identity;
import com.android.internal.app.ISoundTriggerSession;

/**
 * Service interface for a generic sound recognition model.
 *
 * This interface serves as an entry point to establish a session, associated with a client
 * identity, which exposes the actual functionality.
 *
 * @hide
 */
interface ISoundTriggerService {
    /**
     * Creates a new session.
     *
     * This version is intended to be used when the caller itself is the originator of the
     * operations, for authorization purposes.
     *
     * The pid/uid fields are ignored and will be replaced by those provided by binder.
     *
     * 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.
     */
    ISoundTriggerSession attachAsOriginator(in Identity originatorIdentity);

    SoundTrigger.GenericSoundModel getSoundModel(in ParcelUuid soundModelId);

    void updateSoundModel(in SoundTrigger.GenericSoundModel soundModel);

    void deleteSoundModel(in ParcelUuid soundModelId);

    int startRecognition(in ParcelUuid soundModelId, in IRecognitionStatusCallback callback,
         in SoundTrigger.RecognitionConfig config);

    int stopRecognition(in ParcelUuid soundModelId, in IRecognitionStatusCallback callback);

    int loadGenericSoundModel(in SoundTrigger.GenericSoundModel soundModel);
    int loadKeyphraseSoundModel(in SoundTrigger.KeyphraseSoundModel soundModel);

    int startRecognitionForService(in ParcelUuid soundModelId, in Bundle params,
         in ComponentName callbackIntent,in SoundTrigger.RecognitionConfig config);

    int stopRecognitionForService(in ParcelUuid soundModelId);

    int unloadSoundModel(in ParcelUuid soundModelId);

    /** For both ...Intent and ...Service based usage */
    boolean isRecognitionActive(in ParcelUuid parcelUuid);

    int getModelState(in ParcelUuid soundModelId);

    @nullable SoundTrigger.ModuleProperties getModuleProperties();

    int setParameter(in ParcelUuid soundModelId, in ModelParams modelParam,
        int value);

    int getParameter(in ParcelUuid soundModelId, in ModelParams modelParam);

    @nullable SoundTrigger.ModelParamRange queryParameter(in ParcelUuid soundModelId,
        in ModelParams modelParam);
    /**
     * Creates a new session.
     *
     * This version is intended to be used when the caller is acting on behalf of a separate entity
     * (the originator) and the sessions operations are to be accounted against that originator for
     * authorization purposes.
     *
     * The caller must hold the SOUNDTRIGGER_DELEGATE_IDENTITY permission in order to be trusted to
     * provide a reliable originator identity. It should follow the best practices for reliably and
     * securely verifying the identity of the originator.
     *
     * 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.
     */
    ISoundTriggerSession attachAsMiddleman(in Identity middlemanIdentity,
                                           in Identity originatorIdentity);
}
+68 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.internal.app;

import android.app.PendingIntent;
import android.content.ComponentName;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
import android.hardware.soundtrigger.SoundTrigger;
import android.hardware.soundtrigger.ModelParams;
import android.os.Bundle;
import android.os.ParcelUuid;

/**
 * Service interface for a generic sound recognition model.
 * @hide
 */
interface ISoundTriggerSession {

    SoundTrigger.GenericSoundModel getSoundModel(in ParcelUuid soundModelId);

    void updateSoundModel(in SoundTrigger.GenericSoundModel soundModel);

    void deleteSoundModel(in ParcelUuid soundModelId);

    int startRecognition(in ParcelUuid soundModelId, in IRecognitionStatusCallback callback,
         in SoundTrigger.RecognitionConfig config);

    int stopRecognition(in ParcelUuid soundModelId, in IRecognitionStatusCallback callback);

    int loadGenericSoundModel(in SoundTrigger.GenericSoundModel soundModel);
    int loadKeyphraseSoundModel(in SoundTrigger.KeyphraseSoundModel soundModel);

    int startRecognitionForService(in ParcelUuid soundModelId, in Bundle params,
         in ComponentName callbackIntent,in SoundTrigger.RecognitionConfig config);

    int stopRecognitionForService(in ParcelUuid soundModelId);

    int unloadSoundModel(in ParcelUuid soundModelId);

    /** For both ...Intent and ...Service based usage */
    boolean isRecognitionActive(in ParcelUuid parcelUuid);

    int getModelState(in ParcelUuid soundModelId);

    @nullable SoundTrigger.ModuleProperties getModuleProperties();

    int setParameter(in ParcelUuid soundModelId, in ModelParams modelParam,
        int value);

    int getParameter(in ParcelUuid soundModelId, in ModelParams modelParam);

    @nullable SoundTrigger.ModelParamRange queryParameter(in ParcelUuid soundModelId,
        in ModelParams modelParam);
}
+6 −6
Original line number Diff line number Diff line
@@ -35,7 +35,7 @@ import android.os.ParcelUuid;
import android.os.RemoteException;
import android.util.Slog;

import com.android.internal.app.ISoundTriggerService;
import com.android.internal.app.ISoundTriggerSession;

import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -64,7 +64,7 @@ public final class SoundTriggerDetector {

    private final Object mLock = new Object();

    private final ISoundTriggerService mSoundTriggerService;
    private final ISoundTriggerSession mSoundTriggerSession;
    private final UUID mSoundModelId;
    private final Callback mCallback;
    private final Handler mHandler;
@@ -266,9 +266,9 @@ public final class SoundTriggerDetector {
     * This class should be constructed by the {@link SoundTriggerManager}.
     * @hide
     */
    SoundTriggerDetector(ISoundTriggerService soundTriggerService, UUID soundModelId,
    SoundTriggerDetector(ISoundTriggerSession soundTriggerSession, UUID soundModelId,
            @NonNull Callback callback, @Nullable Handler handler) {
        mSoundTriggerService = soundTriggerService;
        mSoundTriggerSession = soundTriggerSession;
        mSoundModelId = soundModelId;
        mCallback = callback;
        if (handler == null) {
@@ -305,7 +305,7 @@ public final class SoundTriggerDetector {

        int status;
        try {
            status = mSoundTriggerService.startRecognition(new ParcelUuid(mSoundModelId),
            status = mSoundTriggerSession.startRecognition(new ParcelUuid(mSoundModelId),
                    mRecognitionCallback, new RecognitionConfig(captureTriggerAudio,
                        allowMultipleTriggers, null, null, audioCapabilities));
        } catch (RemoteException e) {
@@ -321,7 +321,7 @@ public final class SoundTriggerDetector {
    public boolean stopRecognition() {
        int status = STATUS_OK;
        try {
            status = mSoundTriggerService.stopRecognition(new ParcelUuid(mSoundModelId),
            status = mSoundTriggerSession.stopRecognition(new ParcelUuid(mSoundModelId),
                    mRecognitionCallback);
        } catch (RemoteException e) {
            return false;
+36 −17
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.app.ActivityThread;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
@@ -33,6 +34,10 @@ import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
import android.hardware.soundtrigger.SoundTrigger.ModelParamRange;
import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
import android.hardware.soundtrigger.SoundTrigger.SoundModel;
import android.media.permission.ClearCallingIdentityContext;
import android.media.permission.Identity;
import android.media.permission.SafeCloseable;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.ParcelUuid;
@@ -41,6 +46,7 @@ import android.provider.Settings;
import android.util.Slog;

import com.android.internal.app.ISoundTriggerService;
import com.android.internal.app.ISoundTriggerSession;
import com.android.internal.util.Preconditions;

import java.util.HashMap;
@@ -61,7 +67,7 @@ public final class SoundTriggerManager {
    private static final String TAG = "SoundTriggerManager";

    private final Context mContext;
    private final ISoundTriggerService mSoundTriggerService;
    private final ISoundTriggerSession mSoundTriggerSession;

    // Stores a mapping from the sound model UUID to the SoundTriggerInstance created by
    // the createSoundTriggerDetector() call.
@@ -74,7 +80,20 @@ public final class SoundTriggerManager {
        if (DBG) {
            Slog.i(TAG, "SoundTriggerManager created.");
        }
        mSoundTriggerService = soundTriggerService;
        try {
            // This assumes that whoever is calling this ctor is the originator of the operations,
            // as opposed to a service acting on behalf of a separate identity.
            // Services acting on behalf of some other identity should not be using this class at
            // all, but rather directly connect to the server and attach with explicit credentials.
            Identity originatorIdentity = new Identity();
            originatorIdentity.packageName = ActivityThread.currentOpPackageName();

            try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
                mSoundTriggerSession = soundTriggerService.attachAsOriginator(originatorIdentity);
            }
        } catch (RemoteException e) {
            throw e.rethrowAsRuntimeException();
        }
        mContext = context;
        mReceiverInstanceMap = new HashMap<UUID, SoundTriggerDetector>();
    }
@@ -85,7 +104,7 @@ public final class SoundTriggerManager {
    @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
    public void updateModel(Model model) {
        try {
            mSoundTriggerService.updateSoundModel(model.getGenericSoundModel());
            mSoundTriggerSession.updateSoundModel(model.getGenericSoundModel());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
@@ -102,7 +121,7 @@ public final class SoundTriggerManager {
    public Model getModel(UUID soundModelId) {
        try {
            GenericSoundModel model =
                    mSoundTriggerService.getSoundModel(new ParcelUuid(soundModelId));
                    mSoundTriggerSession.getSoundModel(new ParcelUuid(soundModelId));
            if (model == null) {
                return null;
            }
@@ -119,7 +138,7 @@ public final class SoundTriggerManager {
    @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
    public void deleteModel(UUID soundModelId) {
        try {
            mSoundTriggerService.deleteSoundModel(new ParcelUuid(soundModelId));
            mSoundTriggerSession.deleteSoundModel(new ParcelUuid(soundModelId));
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
@@ -149,7 +168,7 @@ public final class SoundTriggerManager {
        if (oldInstance != null) {
            // Shutdown old instance.
        }
        SoundTriggerDetector newInstance = new SoundTriggerDetector(mSoundTriggerService,
        SoundTriggerDetector newInstance = new SoundTriggerDetector(mSoundTriggerSession,
                soundModelId, callback, handler);
        mReceiverInstanceMap.put(soundModelId, newInstance);
        return newInstance;
@@ -309,10 +328,10 @@ public final class SoundTriggerManager {
        try {
            switch (soundModel.getType()) {
                case SoundModel.TYPE_GENERIC_SOUND:
                    return mSoundTriggerService.loadGenericSoundModel(
                    return mSoundTriggerSession.loadGenericSoundModel(
                            (GenericSoundModel) soundModel);
                case SoundModel.TYPE_KEYPHRASE:
                    return mSoundTriggerService.loadKeyphraseSoundModel(
                    return mSoundTriggerSession.loadKeyphraseSoundModel(
                            (KeyphraseSoundModel) soundModel);
                default:
                    Slog.e(TAG, "Unkown model type");
@@ -351,7 +370,7 @@ public final class SoundTriggerManager {
        Preconditions.checkNotNull(config);

        try {
            return mSoundTriggerService.startRecognitionForService(new ParcelUuid(soundModelId),
            return mSoundTriggerSession.startRecognitionForService(new ParcelUuid(soundModelId),
                params, detectionService, config);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
@@ -369,7 +388,7 @@ public final class SoundTriggerManager {
            return STATUS_ERROR;
        }
        try {
            return mSoundTriggerService.stopRecognitionForService(new ParcelUuid(soundModelId));
            return mSoundTriggerSession.stopRecognitionForService(new ParcelUuid(soundModelId));
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
@@ -386,7 +405,7 @@ public final class SoundTriggerManager {
            return STATUS_ERROR;
        }
        try {
            return mSoundTriggerService.unloadSoundModel(
            return mSoundTriggerSession.unloadSoundModel(
                    new ParcelUuid(soundModelId));
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
@@ -404,7 +423,7 @@ public final class SoundTriggerManager {
            return false;
        }
        try {
            return mSoundTriggerService.isRecognitionActive(
            return mSoundTriggerSession.isRecognitionActive(
                    new ParcelUuid(soundModelId));
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
@@ -439,7 +458,7 @@ public final class SoundTriggerManager {
            return STATUS_ERROR;
        }
        try {
            return mSoundTriggerService.getModelState(new ParcelUuid(soundModelId));
            return mSoundTriggerSession.getModelState(new ParcelUuid(soundModelId));
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
@@ -455,7 +474,7 @@ public final class SoundTriggerManager {
    public SoundTrigger.ModuleProperties getModuleProperties() {

        try {
            return mSoundTriggerService.getModuleProperties();
            return mSoundTriggerSession.getModuleProperties();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
@@ -481,7 +500,7 @@ public final class SoundTriggerManager {
    public int setParameter(@Nullable UUID soundModelId,
            @ModelParams int modelParam, int value) {
        try {
            return mSoundTriggerService.setParameter(new ParcelUuid(soundModelId), modelParam,
            return mSoundTriggerSession.setParameter(new ParcelUuid(soundModelId), modelParam,
                    value);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
@@ -504,7 +523,7 @@ public final class SoundTriggerManager {
    public int getParameter(@NonNull UUID soundModelId,
            @ModelParams int modelParam) {
        try {
            return mSoundTriggerService.getParameter(new ParcelUuid(soundModelId), modelParam);
            return mSoundTriggerSession.getParameter(new ParcelUuid(soundModelId), modelParam);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
@@ -524,7 +543,7 @@ public final class SoundTriggerManager {
    public ModelParamRange queryParameter(@Nullable UUID soundModelId,
            @ModelParams int modelParam) {
        try {
            return mSoundTriggerService.queryParameter(new ParcelUuid(soundModelId), modelParam);
            return mSoundTriggerSession.queryParameter(new ParcelUuid(soundModelId), modelParam);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
+6 −1
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.function.BiFunction;

@@ -138,7 +139,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
        mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        mModelDataMap = new HashMap<UUID, ModelData>();
        mKeyphraseUuidMap = new HashMap<Integer, UUID>();
        mPhoneStateListener = new MyCallStateListener();
        if (status != SoundTrigger.STATUS_OK || modules.size() == 0) {
            Slog.w(TAG, "listModules status=" + status + ", # of modules=" + modules.size());
            mModuleProperties = null;
@@ -152,6 +152,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
        if (looper == null) {
            looper = Looper.getMainLooper();
        }
        mPhoneStateListener = new MyCallStateListener(looper);
        if (looper != null) {
            mHandler = new Handler(looper) {
                @Override
@@ -1049,6 +1050,10 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
    }

    class MyCallStateListener extends PhoneStateListener {
        MyCallStateListener(@NonNull Looper looper) {
            super(Objects.requireNonNull(looper));
        }

        @Override
        public void onCallStateChanged(int state, String arg1) {
            if (DBG) Slog.d(TAG, "onCallStateChanged: " + state);
Loading