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

Commit 1cfbb3b4 authored by Atneya Nair's avatar Atneya Nair
Browse files

Add module selection APIs to ST

Configure underlying ST module selection when connecting to STService.
This enables connection to a test HAL implementation.

1. Add listModuleProperties to STService interface.
2. Add ModuleProp argument to STService session attach methods.
3. Existing STService clients select the first module, to retain
   existing behavior.
4. Remove module props cacheing in STHelper.
5. Remove module re-attach on prepareForRec in STHelper, detach is now
   final. Module now re-attaches immediately on HAL death.
6. Explicitly error when no ST module is available in STManager.

Test: Manual verification of assistant/aiai phrase reco
Test: ST clients gracefully reconnect after HAL restart
Test: Manual verification of getModuleProp result
Bug: 269165331
Bug: 269166643
Change-Id: I1be9773aa20d68562154eb9fb9ec9e46583231c9
parent 4c2b1952
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.internal.app;

import android.media.permission.Identity;
import android.hardware.soundtrigger.SoundTrigger;
import com.android.internal.app.ISoundTriggerSession;

/**
@@ -43,6 +44,7 @@ interface ISoundTriggerService {
     * to clean-up whenever that happens.
     */
    ISoundTriggerSession attachAsOriginator(in Identity originatorIdentity,
                                            in SoundTrigger.ModuleProperties moduleProperties,
                                            IBinder client);

    /**
@@ -64,5 +66,12 @@ interface ISoundTriggerService {
     */
    ISoundTriggerSession attachAsMiddleman(in Identity middlemanIdentity,
                                           in Identity originatorIdentity,
                                           in SoundTrigger.ModuleProperties moduleProperties,
                                           IBinder client);

    /**
     * Get available underlying SoundTrigger modules to attach to.
     */
    List<SoundTrigger.ModuleProperties> listModuleProperties(in Identity originatorIdentity);

}
+46 −11
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.hardware.soundtrigger.SoundTrigger;
import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
import android.hardware.soundtrigger.SoundTrigger.ModelParamRange;
import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
import android.hardware.soundtrigger.SoundTrigger.SoundModel;
import android.media.permission.ClearCallingIdentityContext;
@@ -52,6 +53,7 @@ import com.android.internal.app.ISoundTriggerSession;
import com.android.internal.util.Preconditions;

import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.UUID;

@@ -92,8 +94,16 @@ public final class SoundTriggerManager {
            originatorIdentity.packageName = ActivityThread.currentOpPackageName();

            try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
                mSoundTriggerSession = soundTriggerService.attachAsOriginator(originatorIdentity,
                List<ModuleProperties> modulePropertiesList = soundTriggerService
                        .listModuleProperties(originatorIdentity);
                if (!modulePropertiesList.isEmpty()) {
                    mSoundTriggerSession = soundTriggerService.attachAsOriginator(
                                                originatorIdentity,
                                                modulePropertiesList.get(0),
                                                mBinderToken);
                } else {
                    mSoundTriggerSession = null;
                }
            }
        } catch (RemoteException e) {
            throw e.rethrowAsRuntimeException();
@@ -110,6 +120,9 @@ public final class SoundTriggerManager {
    @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
    @Deprecated
    public void updateModel(Model model) {
        if (mSoundTriggerSession == null) {
            throw new IllegalStateException("No underlying SoundTriggerModule available");
        }
        try {
            mSoundTriggerSession.updateSoundModel(model.getGenericSoundModel());
        } catch (RemoteException e) {
@@ -128,6 +141,9 @@ public final class SoundTriggerManager {
    @Nullable
    @Deprecated
    public Model getModel(UUID soundModelId) {
        if (mSoundTriggerSession == null) {
            throw new IllegalStateException("No underlying SoundTriggerModule available");
        }
        try {
            GenericSoundModel model =
                    mSoundTriggerSession.getSoundModel(new ParcelUuid(soundModelId));
@@ -149,6 +165,10 @@ public final class SoundTriggerManager {
    @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
    @Deprecated
    public void deleteModel(UUID soundModelId) {
        if (mSoundTriggerSession == null) {
            throw new IllegalStateException("No underlying SoundTriggerModule available");
        }

        try {
            mSoundTriggerSession.deleteSoundModel(new ParcelUuid(soundModelId));
        } catch (RemoteException e) {
@@ -176,7 +196,7 @@ public final class SoundTriggerManager {
    @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
    public SoundTriggerDetector createSoundTriggerDetector(UUID soundModelId,
            @NonNull SoundTriggerDetector.Callback callback, @Nullable Handler handler) {
        if (soundModelId == null) {
        if (soundModelId == null || mSoundTriggerSession == null) {
            return null;
        }

@@ -342,7 +362,7 @@ public final class SoundTriggerManager {
    @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
    @UnsupportedAppUsage
    public int loadSoundModel(SoundModel soundModel) {
        if (soundModel == null) {
        if (soundModel == null || mSoundTriggerSession == null) {
            return STATUS_ERROR;
        }

@@ -389,7 +409,9 @@ public final class SoundTriggerManager {
        Preconditions.checkNotNull(soundModelId);
        Preconditions.checkNotNull(detectionService);
        Preconditions.checkNotNull(config);

        if (mSoundTriggerSession == null) {
            return STATUS_ERROR;
        }
        try {
            return mSoundTriggerSession.startRecognitionForService(new ParcelUuid(soundModelId),
                params, detectionService, config);
@@ -405,7 +427,7 @@ public final class SoundTriggerManager {
    @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public int stopRecognition(UUID soundModelId) {
        if (soundModelId == null) {
        if (soundModelId == null || mSoundTriggerSession == null) {
            return STATUS_ERROR;
        }
        try {
@@ -422,7 +444,7 @@ public final class SoundTriggerManager {
    @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public int unloadSoundModel(UUID soundModelId) {
        if (soundModelId == null) {
        if (soundModelId == null || mSoundTriggerSession == null) {
            return STATUS_ERROR;
        }
        try {
@@ -440,7 +462,7 @@ public final class SoundTriggerManager {
    @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
    @UnsupportedAppUsage
    public boolean isRecognitionActive(UUID soundModelId) {
        if (soundModelId == null) {
        if (soundModelId == null || mSoundTriggerSession == null) {
            return false;
        }
        try {
@@ -475,7 +497,7 @@ public final class SoundTriggerManager {
    @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
    @UnsupportedAppUsage
    public int getModelState(UUID soundModelId) {
        if (soundModelId == null) {
        if (soundModelId == null || mSoundTriggerSession == null) {
            return STATUS_ERROR;
        }
        try {
@@ -492,8 +514,10 @@ public final class SoundTriggerManager {
     */
    @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
    @Nullable
    public SoundTrigger.ModuleProperties getModuleProperties() {

    public ModuleProperties getModuleProperties() {
        if (mSoundTriggerSession == null) {
            return null;
        }
        try {
            return mSoundTriggerSession.getModuleProperties();
        } catch (RemoteException e) {
@@ -520,6 +544,10 @@ public final class SoundTriggerManager {
    @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
    public int setParameter(@Nullable UUID soundModelId,
            @ModelParams int modelParam, int value) {
        if (mSoundTriggerSession == null) {
            return SoundTrigger.STATUS_INVALID_OPERATION;
        }

        try {
            return mSoundTriggerSession.setParameter(new ParcelUuid(soundModelId), modelParam,
                    value);
@@ -543,6 +571,10 @@ public final class SoundTriggerManager {
    @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
    public int getParameter(@NonNull UUID soundModelId,
            @ModelParams int modelParam) {
        if (mSoundTriggerSession == null) {
            throw new IllegalArgumentException("Sound model is not loaded: "
                            + soundModelId.toString());
        }
        try {
            return mSoundTriggerSession.getParameter(new ParcelUuid(soundModelId), modelParam);
        } catch (RemoteException e) {
@@ -563,6 +595,9 @@ public final class SoundTriggerManager {
    @Nullable
    public ModelParamRange queryParameter(@Nullable UUID soundModelId,
            @ModelParams int modelParam) {
        if (mSoundTriggerSession == null) {
            return null;
        }
        try {
            return mSoundTriggerSession.queryParameter(new ParcelUuid(soundModelId), modelParam);
        } catch (RemoteException e) {
+28 −56
Original line number Diff line number Diff line
@@ -56,9 +56,12 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * Helper for {@link SoundTrigger} APIs. Supports two types of models:
@@ -84,10 +87,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {

    private static final int INVALID_VALUE = Integer.MIN_VALUE;

    /** The {@link ModuleProperties} for the system, or null if none exists. */
    final ModuleProperties mModuleProperties;

    /** The properties for the DSP module */
    private SoundTriggerModule mModule;
    private final Object mLock = new Object();
    private final Context mContext;
@@ -114,7 +113,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {

    private PowerSaveModeListener mPowerSaveModeListener;

    private final SoundTriggerModuleProvider mModuleProvider;

    // Handler to process call state changes will delay to allow time for the audio
    // and sound trigger HALs to process the end of call notifications
@@ -123,46 +121,24 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
    private static final int MSG_CALL_STATE_CHANGED = 0;
    private static final int CALL_INACTIVE_MSG_DELAY_MS = 1000;

    /**
     * Provider interface for retrieving SoundTriggerModule instances
     */
    public interface SoundTriggerModuleProvider {
        /**
         * Populate module properties for all available modules
         *
         * @param modules List of ModuleProperties to be populated
         * @return Status int 0 on success.
         */
        int listModuleProperties(@NonNull ArrayList<SoundTrigger.ModuleProperties> modules);

        /**
         * Get SoundTriggerModule based on {@link SoundTrigger.ModuleProperties#getId()}
         *
         * @param moduleId Module ID
         * @param statusListener Client listener to be associated with the returned module
         * @return Module associated with moduleId
         */
        SoundTriggerModule getModule(int moduleId, SoundTrigger.StatusListener statusListener);
    }
    // TODO(b/269366605) Temporary solution to query correct moduleProperties
    private final int mModuleId;
    private final Function<SoundTrigger.StatusListener, SoundTriggerModule> mModuleProvider;
    private final Supplier<List<ModuleProperties>> mModulePropertiesProvider;

    SoundTriggerHelper(Context context, SoundTriggerModuleProvider moduleProvider) {
        ArrayList <ModuleProperties> modules = new ArrayList<>();
        mModuleProvider = moduleProvider;
        int status = mModuleProvider.listModuleProperties(modules);
    SoundTriggerHelper(Context context,
            @NonNull Function<SoundTrigger.StatusListener, SoundTriggerModule> moduleProvider,
            int moduleId,
            @NonNull Supplier<List<ModuleProperties>> modulePropertiesProvider) {
        mModuleId = moduleId;
        mContext = context;
        mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        mModelDataMap = new HashMap<UUID, ModelData>();
        mKeyphraseUuidMap = new HashMap<Integer, UUID>();
        if (status != SoundTrigger.STATUS_OK || modules.size() == 0) {
            Slog.w(TAG, "listModules status=" + status + ", # of modules=" + modules.size());
            mModuleProperties = null;
            mModule = null;
        } else {
            // TODO: Figure out how to determine which module corresponds to the DSP hardware.
            mModuleProperties = modules.get(0);
        }

        mModuleProvider = moduleProvider;
        mModulePropertiesProvider = modulePropertiesProvider;
        mModule = mModuleProvider.apply(this);
        Looper looper = Looper.myLooper();
        if (looper == null) {
            looper = Looper.getMainLooper();
@@ -245,7 +221,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
                        + " soundModel=" + soundModel + ", callback=" + callback.asBinder()
                        + ", recognitionConfig=" + recognitionConfig
                        + ", runInBatterySaverMode=" + runInBatterySaverMode);
                Slog.d(TAG, "moduleProperties=" + mModuleProperties);
                dumpModelStateLocked();
            }

@@ -289,13 +264,10 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
    }

    private int prepareForRecognition(ModelData modelData) {
        if (mModule == null) {
            mModule = mModuleProvider.getModule(mModuleProperties.getId(), this);
        if (mModule == null) {
            Slog.w(TAG, "prepareForRecognition: cannot attach to sound trigger module");
            return STATUS_ERROR;
        }
        }
        // Load the model if it is not loaded.
        if (!modelData.isModelLoaded()) {
            // Before we try and load this model, we should first make sure that any other
@@ -336,11 +308,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
            IRecognitionStatusCallback callback, RecognitionConfig recognitionConfig,
            int keyphraseId, boolean runInBatterySaverMode) {
        synchronized (mLock) {
            if (mModuleProperties == null) {
                Slog.w(TAG, "Attempting startRecognition without the capability");
                return STATUS_ERROR;
            }

            IRecognitionStatusCallback oldCallback = modelData.getCallback();
            if (oldCallback != null && oldCallback.asBinder() != callback.asBinder()) {
                Slog.w(TAG, "Canceling previous recognition for model id: "
@@ -486,8 +453,8 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
            if (callback == null) {
                return STATUS_ERROR;
            }
            if (mModuleProperties == null || mModule == null) {
                Slog.w(TAG, "Attempting stopRecognition without the capability");
            if (mModule == null) {
                Slog.w(TAG, "Attempting stopRecognition after detach");
                return STATUS_ERROR;
            }

@@ -563,7 +530,13 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
    }

    public ModuleProperties getModuleProperties() {
        return mModuleProperties;
        for (ModuleProperties moduleProperties : mModulePropertiesProvider.get()) {
            if (moduleProperties.getId() == mModuleId) {
                return moduleProperties;
            }
        }
        Slog.e(TAG, "Module properties not found for existing moduleId " + mModuleId);
        return null;
    }

    int unloadKeyphraseSoundModel(int keyphraseId) {
@@ -1027,7 +1000,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
            internalClearGlobalStateLocked();
            if (mModule != null) {
                mModule.detach();
                mModule = null;
                mModule = mModuleProvider.apply(this);
            }
        }
    }
@@ -1098,7 +1071,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
    void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        synchronized (mLock) {
            pw.print("  module properties=");
            pw.println(mModuleProperties == null ? "null" : mModuleProperties);
            pw.print("  call active=");
            pw.println(mCallActive);
            pw.println("  SoundTrigger Power State=" + mSoundTriggerPowerSaveMode);
@@ -1444,7 +1416,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
    // Computes whether we have any recognition running at all (voice or generic). Sets
    // the mRecognitionRequested variable with the result.
    private boolean computeRecognitionRequestedLocked() {
        if (mModuleProperties == null || mModule == null) {
        if (mModule == null) {
            mRecognitionRequested = false;
            return mRecognitionRequested;
        }
+7 −1
Original line number Diff line number Diff line
@@ -26,12 +26,14 @@ import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
import android.hardware.soundtrigger.SoundTrigger.ModelParamRange;
import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
import android.media.permission.Identity;
import android.os.IBinder;

import com.android.server.voiceinteraction.VoiceInteractionManagerService;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.List;

/**
 * Provides a local service for managing voice-related recoginition models. This is primarily used
@@ -46,7 +48,11 @@ public interface SoundTriggerInternal {
    int STATUS_ERROR = SoundTrigger.STATUS_ERROR;
    int STATUS_OK = SoundTrigger.STATUS_OK;

    Session attach(@NonNull IBinder client);
    // Attach to a specific underlying STModule
    Session attach(@NonNull IBinder client, ModuleProperties underlyingModule);

    // Enumerate possible STModules to attach to
    List<ModuleProperties> listModuleProperties(Identity originatorIdentity);

    /**
     * Dumps service-wide information.
+57 −25
Original line number Diff line number Diff line
@@ -51,7 +51,6 @@ import android.hardware.soundtrigger.SoundTrigger.ModelParamRange;
import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
import android.hardware.soundtrigger.SoundTrigger.SoundModel;
import android.hardware.soundtrigger.SoundTriggerModule;
import android.media.AudioAttributes;
import android.media.AudioFormat;
import android.media.AudioRecord;
@@ -89,6 +88,7 @@ import com.android.server.utils.EventLogger;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;
@@ -215,47 +215,69 @@ public class SoundTriggerService extends SystemService {
        }
    }

    private SoundTriggerHelper newSoundTriggerHelper() {
    private SoundTriggerHelper newSoundTriggerHelper(@NonNull ModuleProperties moduleProperties) {
        Identity middlemanIdentity = new Identity();
        middlemanIdentity.packageName = ActivityThread.currentOpPackageName();

        Identity originatorIdentity = IdentityContext.getNonNull();

        return new SoundTriggerHelper(mContext,
                new SoundTriggerHelper.SoundTriggerModuleProvider() {
                    @Override
                    public int listModuleProperties(ArrayList<ModuleProperties> modules) {
                        return SoundTrigger.listModulesAsMiddleman(modules, middlemanIdentity,
        ArrayList<ModuleProperties> moduleList = new ArrayList<>();
        SoundTrigger.listModulesAsMiddleman(moduleList, middlemanIdentity,
                                        originatorIdentity);
                    }

                    @Override
                    public SoundTriggerModule getModule(int moduleId,
                            SoundTrigger.StatusListener statusListener) {
                        return SoundTrigger.attachModuleAsMiddleman(moduleId, statusListener, null,
                                middlemanIdentity, originatorIdentity);
        if (!moduleList.contains(moduleProperties)) {
            throw new IllegalArgumentException("Invalid module properties");
        }

        int moduleId = moduleProperties.getId();

        return new SoundTriggerHelper(
                mContext,
                (SoundTrigger.StatusListener statusListener) ->
                                        SoundTrigger.attachModuleAsMiddleman(
                                        moduleId, statusListener, null /* handler */,
                                        middlemanIdentity, originatorIdentity),
                moduleId,
                () -> {
                    ArrayList<ModuleProperties> modulePropList = new ArrayList<>();
                    SoundTrigger.listModulesAsMiddleman(modulePropList, middlemanIdentity,
                                                    originatorIdentity);
                    return modulePropList;
                });
    }

    class SoundTriggerServiceStub extends ISoundTriggerService.Stub {
        @Override
        public ISoundTriggerSession attachAsOriginator(Identity originatorIdentity,
        public ISoundTriggerSession attachAsOriginator(@NonNull Identity originatorIdentity,
                @NonNull ModuleProperties moduleProperties,
                @NonNull IBinder client) {
            try (SafeCloseable ignored = PermissionUtil.establishIdentityDirect(
                    originatorIdentity)) {
                return new SoundTriggerSessionStub(client);
                return new SoundTriggerSessionStub(client, newSoundTriggerHelper(moduleProperties));
            }
        }

        @Override
        public ISoundTriggerSession attachAsMiddleman(Identity originatorIdentity,
                Identity middlemanIdentity,
        public ISoundTriggerSession attachAsMiddleman(@NonNull Identity originatorIdentity,
                @NonNull Identity middlemanIdentity,
                @NonNull ModuleProperties moduleProperties,
                @NonNull IBinder client) {
            try (SafeCloseable ignored = PermissionUtil.establishIdentityIndirect(mContext,
                    SOUNDTRIGGER_DELEGATE_IDENTITY, middlemanIdentity,
                    originatorIdentity)) {
                return new SoundTriggerSessionStub(client);
                return new SoundTriggerSessionStub(client, newSoundTriggerHelper(moduleProperties));
            }
        }

        @Override
        public List<ModuleProperties> listModuleProperties(@NonNull Identity originatorIdentity) {
            try (SafeCloseable ignored = PermissionUtil.establishIdentityDirect(
                    originatorIdentity)) {
                Identity middlemanIdentity = new Identity();
                middlemanIdentity.packageName = ActivityThread.currentOpPackageName();
                ArrayList<ModuleProperties> moduleList = new ArrayList<>();
                SoundTrigger.listModulesAsMiddleman(moduleList, middlemanIdentity,
                                                originatorIdentity);
                return moduleList;
            }
        }
    }
@@ -269,8 +291,8 @@ public class SoundTriggerService extends SystemService {
        private final Object mCallbacksLock = new Object();
        private final TreeMap<UUID, IRecognitionStatusCallback> mCallbacks = new TreeMap<>();

        SoundTriggerSessionStub(@NonNull IBinder client) {
            mSoundTriggerHelper = newSoundTriggerHelper();
        SoundTriggerSessionStub(@NonNull IBinder client, SoundTriggerHelper soundTriggerHelper) {
            mSoundTriggerHelper = soundTriggerHelper;
            mClient = client;
            mOriginatorIdentity = IdentityContext.getNonNull();
            try {
@@ -1615,8 +1637,18 @@ public class SoundTriggerService extends SystemService {
        }

        @Override
        public Session attach(@NonNull IBinder client) {
            return new SessionImpl(newSoundTriggerHelper(), client);
        public Session attach(@NonNull IBinder client, ModuleProperties underlyingModule) {
            return new SessionImpl(newSoundTriggerHelper(underlyingModule), client);
        }

        @Override
        public List<ModuleProperties> listModuleProperties(Identity originatorIdentity) {
            Identity middlemanIdentity = new Identity();
            middlemanIdentity.packageName = ActivityThread.currentOpPackageName();
            ArrayList<ModuleProperties> moduleList = new ArrayList<>();
            SoundTrigger.listModulesAsMiddleman(moduleList, middlemanIdentity,
                                            originatorIdentity);
            return moduleList;
        }

        @Override
Loading