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

Commit 43993b70 authored by Eric Laurent's avatar Eric Laurent Committed by Android (Google) Code Review
Browse files

Merge "RESTRICT AUTOMERGE Restart recognition when failing to deliver event" into sc-dev

parents c630f879 0896e161
Loading
Loading
Loading
Loading
+5 −13
Original line number Diff line number Diff line
@@ -133,13 +133,8 @@ public class SoundTriggerMiddlewarePermission implements ISoundTriggerMiddleware
     * Throws a {@link SecurityException} iff the originator has permission to receive data.
     */
    void enforcePermissionsForDataDelivery(@NonNull Identity identity, @NonNull String reason) {
        // TODO(b/186164881): remove
        // START TEMP HACK
        enforcePermissionForPreflight(mContext, identity, RECORD_AUDIO);
        int hotwordOp = AppOpsManager.strOpToOp(AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD);
        mContext.getSystemService(AppOpsManager.class).noteOpNoThrow(hotwordOp, identity.uid,
                identity.packageName, identity.attributionTag, reason);
        // END TEMP HACK
        enforcePermissionForDataDelivery(mContext, identity, RECORD_AUDIO,
                reason);
        enforcePermissionForDataDelivery(mContext, identity, CAPTURE_AUDIO_HOTWORD,
                reason);
    }
@@ -167,8 +162,8 @@ public class SoundTriggerMiddlewarePermission implements ISoundTriggerMiddleware

    /**
     * Throws a {@link SecurityException} if originator permanently doesn't have the given
     * permission, or a {@link ServiceSpecificException} with a {@link
     * Status#TEMPORARY_PERMISSION_DENIED} if caller originator doesn't have the given permission.
     * permission.
     * Soft (temporary) denials are considered OK for preflight purposes.
     *
     * @param context    A {@link Context}, used for permission checks.
     * @param identity   The identity to check.
@@ -180,15 +175,12 @@ public class SoundTriggerMiddlewarePermission implements ISoundTriggerMiddleware
                permission);
        switch (status) {
            case PermissionChecker.PERMISSION_GRANTED:
            case PermissionChecker.PERMISSION_SOFT_DENIED:
                return;
            case PermissionChecker.PERMISSION_HARD_DENIED:
                throw new SecurityException(
                        String.format("Failed to obtain permission %s for identity %s", permission,
                                ObjectPrinter.print(identity, true, 16)));
            case PermissionChecker.PERMISSION_SOFT_DENIED:
                throw new ServiceSpecificException(Status.TEMPORARY_PERMISSION_DENIED,
                        String.format("Failed to obtain permission %s for identity %s", permission,
                                ObjectPrinter.print(identity, true, 16)));
            default:
                throw new RuntimeException("Unexpected perimission check result.");
        }
+40 −0
Original line number Diff line number Diff line
@@ -318,6 +318,8 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware
         */
        private Map<Integer, ModelParameterRange> parameterSupport = new HashMap<>();

        private RecognitionConfig mConfig;

        /**
         * Check that the given parameter is known to be supported for this model.
         *
@@ -369,6 +371,14 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware
        void setActivityState(Activity activity) {
            mActivityState.set(activity.ordinal());
        }

        void setRecognitionConfig(@NonNull RecognitionConfig config) {
            mConfig = config;
        }

        RecognitionConfig getRecognitionConfig() {
            return mConfig;
        }
    }

    /**
@@ -502,6 +512,7 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware
                    // Normally, we would set the state after the operation succeeds. However, since
                    // the activity state may be reset outside of the lock, we set it here first,
                    // and reset it in case of exception.
                    modelState.setRecognitionConfig(config);
                    modelState.setActivityState(ModelState.Activity.ACTIVE);
                    mDelegate.startRecognition(modelHandle, config);
                } catch (Exception e) {
@@ -542,6 +553,27 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware
            }
        }

        private void restartIfIntercepted(int modelHandle) {
            synchronized (SoundTriggerMiddlewareValidation.this) {
                // State validation.
                if (mState == ModuleStatus.DETACHED) {
                    return;
                }
                ModelState modelState = mLoadedModels.get(modelHandle);
                if (modelState == null
                        || modelState.getActivityState() != ModelState.Activity.INTERCEPTED) {
                    return;
                }
                try {
                    mDelegate.startRecognition(modelHandle, modelState.getRecognitionConfig());
                    modelState.setActivityState(ModelState.Activity.ACTIVE);
                    Log.i(TAG, "Restarted intercepted model " + modelHandle);
                } catch (Exception e) {
                    Log.i(TAG, "Failed to restart intercepted model " + modelHandle, e);
                }
            }
        }

        @Override
        public void forceRecognitionEvent(int modelHandle) {
            // Input validation (always valid).
@@ -753,6 +785,10 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware
                    Log.e(TAG, "Client callback exception.", e);
                    if (event.status != RecognitionStatus.FORCED) {
                        modelState.setActivityState(ModelState.Activity.INTERCEPTED);
                        // If we failed to deliver an actual event to the client, they would never
                        // know to restart it whenever circumstances change. Thus, we restart it
                        // here. We do this from a separate thread to avoid any race conditions.
                        new Thread(() -> restartIfIntercepted(modelHandle)).start();
                    }
                }
            }
@@ -780,6 +816,10 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware
                    Log.e(TAG, "Client callback exception.", e);
                    if (event.common.status != RecognitionStatus.FORCED) {
                        modelState.setActivityState(ModelState.Activity.INTERCEPTED);
                        // If we failed to deliver an actual event to the client, they would never
                        // know to restart it whenever circumstances change. Thus, we restart it
                        // here. We do this from a separate thread to avoid any race conditions.
                        new Thread(() -> restartIfIntercepted(modelHandle)).start();
                    }
                }
            }