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

Commit 93731813 authored by Atneya Nair's avatar Atneya Nair Committed by Automerger Merge Worker
Browse files

Merge "Add AppOps listening to STService" into udc-dev am: 3d360a0e

parents 7fc54b47 3d360a0e
Loading
Loading
Loading
Loading
+26 −4
Original line number Diff line number Diff line
@@ -119,6 +119,9 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
    @GuardedBy("mLock")
    private SoundTriggerDeviceState mDeviceState = SoundTriggerDeviceState.DISABLE;

    @GuardedBy("mLock")
    private boolean mIsAppOpPermitted = true;

    SoundTriggerHelper(Context context, EventLogger eventLogger,
            @NonNull Function<SoundTrigger.StatusListener, SoundTriggerModule> moduleProvider,
            int moduleId,
@@ -323,7 +326,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
            modelData.setRunInBatterySaverMode(runInBatterySaverMode);
            modelData.setSoundModel(soundModel);

            if (isRecognitionAllowedByDeviceState(modelData)) {
            if (isRecognitionAllowed(modelData)) {
                int startRecoResult = updateRecognitionLocked(modelData,
                        false /* Don't notify for synchronous calls */);
                if (startRecoResult == SoundTrigger.STATUS_OK) {
@@ -613,6 +616,16 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
        }
    }

    public void onAppOpStateChanged(boolean isPermitted) {
        synchronized (mLock) {
            if (mIsAppOpPermitted == isPermitted) {
                return;
            }
            mIsAppOpPermitted = isPermitted;
            updateAllRecognitionsLocked();
        }
    }

    public int getGenericModelState(UUID modelId) {
        synchronized (mLock) {
            MetricsLogger.count(mContext, "sth_get_generic_model_state", 1);
@@ -782,6 +795,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
        return event instanceof KeyphraseRecognitionEvent;
    }

    @GuardedBy("mLock")
    private void onGenericRecognitionLocked(GenericRecognitionEvent event) {
        MetricsLogger.count(mContext, "sth_generic_recognition_event", 1);
        if (event.status != SoundTrigger.RECOGNITION_STATUS_SUCCESS
@@ -866,6 +880,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
        }
    }

    @GuardedBy("mLock")
    private void onResourcesAvailableLocked() {
        mEventLogger.enqueue(new SessionEvent(Type.RESOURCES_AVAILABLE, null));
        updateAllRecognitionsLocked();
@@ -911,6 +926,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
        return keyphraseExtras[0].id;
    }

    @GuardedBy("mLock")
    private void onKeyphraseRecognitionLocked(KeyphraseRecognitionEvent event) {
        Slog.i(TAG, "Recognition success");
        MetricsLogger.count(mContext, "sth_keyphrase_recognition_event", 1);
@@ -956,6 +972,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
        }
    }

    @GuardedBy("mLock")
    private void updateAllRecognitionsLocked() {
        // updateRecognitionLocked can possibly update the list of models
        ArrayList<ModelData> modelDatas = new ArrayList<ModelData>(mModelDataMap.values());
@@ -964,8 +981,9 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
        }
    }

    @GuardedBy("mLock")
    private int updateRecognitionLocked(ModelData model, boolean notifyClientOnError) {
        boolean shouldStartModel = model.isRequested() && isRecognitionAllowedByDeviceState(model);
        boolean shouldStartModel = model.isRequested() && isRecognitionAllowed(model);
        if (shouldStartModel == model.isModelStarted()) {
            // No-op.
            return STATUS_OK;
@@ -1184,7 +1202,10 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
     * @return True if recognition is allowed to run at this time. False if not.
     */
    @GuardedBy("mLock")
    private boolean isRecognitionAllowedByDeviceState(ModelData modelData) {
    private boolean isRecognitionAllowed(ModelData modelData) {
        if (!mIsAppOpPermitted) {
            return false;
        }
        return switch (mDeviceState) {
            case DISABLE -> false;
            case CRITICAL -> modelData.shouldRunInBatterySaverMode();
@@ -1195,6 +1216,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {

    // A single routine that implements the start recognition logic for both generic and keyphrase
    // models.
    @GuardedBy("mLock")
    private int startRecognitionLocked(ModelData modelData, boolean notifyClientOnError) {
        IRecognitionStatusCallback callback = modelData.getCallback();
        RecognitionConfig config = modelData.getRecognitionConfig();
@@ -1205,7 +1227,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
            return STATUS_ERROR;
        }

        if (!isRecognitionAllowedByDeviceState(modelData)) {
        if (!isRecognitionAllowed(modelData)) {
            // Nothing to do here.
            Slog.w(TAG, "startRecognition requested but not allowed.");
            MetricsLogger.count(mContext, "sth_start_recognition_not_allowed", 1);
+65 −2
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityThread;
import android.app.AppOpsManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -111,6 +112,7 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.function.Consumer;
import java.util.List;
import java.util.Set;
import java.util.Deque;
@@ -236,6 +238,8 @@ public class SoundTriggerService extends SystemService {
    private final DeviceStateHandler mDeviceStateHandler;
    private final Executor mDeviceStateHandlerExecutor = Executors.newSingleThreadExecutor();
    private PhoneCallStateHandler mPhoneCallStateHandler;
    private AppOpsManager mAppOpsManager;
    private PackageManager mPackageManager;

    public SoundTriggerService(Context context) {
        super(context);
@@ -258,6 +262,8 @@ public class SoundTriggerService extends SystemService {
        Slog.d(TAG, "onBootPhase: " + phase + " : " + isSafeMode());
        if (PHASE_THIRD_PARTY_APPS_CAN_START == phase) {
            mDbHelper = new SoundTriggerDbHelper(mContext);
            mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
            mPackageManager = mContext.getPackageManager();
            final PowerManager powerManager = mContext.getSystemService(PowerManager.class);
            // Hook up power state listener
            mContext.registerReceiver(
@@ -349,6 +355,44 @@ public class SoundTriggerService extends SystemService {
        }
    }

    class MyAppOpsListener implements AppOpsManager.OnOpChangedListener {
        private final Identity mOriginatorIdentity;
        private final Consumer<Boolean> mOnOpModeChanged;

        MyAppOpsListener(Identity originatorIdentity, Consumer<Boolean> onOpModeChanged) {
            mOriginatorIdentity = Objects.requireNonNull(originatorIdentity);
            mOnOpModeChanged = Objects.requireNonNull(onOpModeChanged);
            // Validate package name
            try {
                int uid = mPackageManager.getPackageUid(mOriginatorIdentity.packageName,
                        PackageManager.PackageInfoFlags.of(0));
                if (uid != mOriginatorIdentity.uid) {
                    throw new SecurityException("Package name: " +
                            mOriginatorIdentity.packageName + "with uid: " + uid
                            + "attempted to spoof as: " + mOriginatorIdentity.uid);
                }
            } catch (PackageManager.NameNotFoundException e) {
                throw new SecurityException("Package name not found: "
                        + mOriginatorIdentity.packageName);
            }
        }

        @Override
        public void onOpChanged(String op, String packageName) {
            if (!Objects.equals(op, AppOpsManager.OPSTR_RECORD_AUDIO)) {
                return;
            }
            final int mode = mAppOpsManager.checkOpNoThrow(
                    AppOpsManager.OPSTR_RECORD_AUDIO, mOriginatorIdentity.uid,
                    mOriginatorIdentity.packageName);
            mOnOpModeChanged.accept(mode == AppOpsManager.MODE_ALLOWED);
        }

        void forceOpChangeRefresh() {
            onOpChanged(AppOpsManager.OPSTR_RECORD_AUDIO, mOriginatorIdentity.packageName);
        }
    }

    class SoundTriggerServiceStub extends ISoundTriggerService.Stub {
        @Override
        public ISoundTriggerSession attachAsOriginator(@NonNull Identity originatorIdentity,
@@ -463,6 +507,7 @@ public class SoundTriggerService extends SystemService {
        private final Object mCallbacksLock = new Object();
        private final TreeMap<UUID, IRecognitionStatusCallback> mCallbacks = new TreeMap<>();
        private final EventLogger mEventLogger;
        private final MyAppOpsListener mAppOpsListener;

        SoundTriggerSessionStub(@NonNull IBinder client,
                SoundTriggerHelper soundTriggerHelper, EventLogger eventLogger) {
@@ -479,6 +524,12 @@ public class SoundTriggerService extends SystemService {
            }
            mListener = (SoundTriggerDeviceState state)
                    -> mSoundTriggerHelper.onDeviceStateChanged(state);
            mAppOpsListener = new MyAppOpsListener(mOriginatorIdentity,
                    mSoundTriggerHelper::onAppOpStateChanged);
            mAppOpsListener.forceOpChangeRefresh();
            mAppOpsManager.startWatchingMode(AppOpsManager.OPSTR_RECORD_AUDIO,
                    mOriginatorIdentity.packageName, AppOpsManager.WATCH_FOREGROUND_CHANGES,
                    mAppOpsListener);
            mDeviceStateHandler.registerListener(mListener);
        }

@@ -930,6 +981,9 @@ public class SoundTriggerService extends SystemService {
        }

        private void detach() {
            if (mAppOpsListener != null) {
                mAppOpsManager.stopWatchingMode(mAppOpsListener);
            }
            mDeviceStateHandler.unregisterListener(mListener);
            mSoundTriggerHelper.detach();
            detachSessionLogger(mEventLogger);
@@ -945,9 +999,8 @@ public class SoundTriggerService extends SystemService {
        }

        private void enforceDetectionPermissions(ComponentName detectionService) {
            PackageManager packageManager = mContext.getPackageManager();
            String packageName = detectionService.getPackageName();
            if (packageManager.checkPermission(
            if (mPackageManager.checkPermission(
                        Manifest.permission.CAPTURE_AUDIO_HOTWORD, packageName)
                    != PackageManager.PERMISSION_GRANTED) {
                throw new SecurityException(detectionService.getPackageName() + " does not have"
@@ -1635,6 +1688,7 @@ public class SoundTriggerService extends SystemService {
            private final EventLogger mEventLogger;
            private final Identity mOriginatorIdentity;
            private final @NonNull DeviceStateListener mListener;
            private final MyAppOpsListener mAppOpsListener;

            private final SparseArray<UUID> mModelUuid = new SparseArray<>(1);

@@ -1655,6 +1709,12 @@ public class SoundTriggerService extends SystemService {
                }
                mListener = (SoundTriggerDeviceState state)
                        -> mSoundTriggerHelper.onDeviceStateChanged(state);
                mAppOpsListener = new MyAppOpsListener(mOriginatorIdentity,
                        mSoundTriggerHelper::onAppOpStateChanged);
                mAppOpsListener.forceOpChangeRefresh();
                mAppOpsManager.startWatchingMode(AppOpsManager.OPSTR_RECORD_AUDIO,
                        mOriginatorIdentity.packageName, AppOpsManager.WATCH_FOREGROUND_CHANGES,
                        mAppOpsListener);
                mDeviceStateHandler.registerListener(mListener);
            }

@@ -1722,6 +1782,9 @@ public class SoundTriggerService extends SystemService {
            }

            private void detachInternal() {
                if (mAppOpsListener != null) {
                    mAppOpsManager.stopWatchingMode(mAppOpsListener);
                }
                mEventLogger.enqueue(new SessionEvent(Type.DETACH, null));
                detachSessionLogger(mEventLogger);
                mDeviceStateHandler.unregisterListener(mListener);