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

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

Merge "Restart recognition when failing to deliver event"

parents 4211dbca d3bee4f4
Loading
Loading
Loading
Loading
+5 −13
Original line number Diff line number Diff line
@@ -121,13 +121,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);
    }
@@ -155,8 +150,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.
@@ -168,15 +163,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.");
        }
+35 −0
Original line number Diff line number Diff line
@@ -279,6 +279,9 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware
        /** Activity state. */
        Activity activityState = Activity.LOADED;

        /** Recognition config, used to start the model. */
        RecognitionConfig config;

        /** Human-readable description of the model. */
        final String description;

@@ -455,6 +458,7 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware
                // From here on, every exception isn't client's fault.
                try {
                    mDelegate.startRecognition(modelHandle, config);
                    modelState.config = config;
                    modelState.activityState = ModelState.Activity.ACTIVE;
                } catch (Exception e) {
                    throw handleException(e);
@@ -512,6 +516,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.activityState != ModelState.Activity.INTERCEPTED) {
                    return;
                }
                try {
                    mDelegate.startRecognition(modelHandle, modelState.config);
                    modelState.activityState = 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).
@@ -720,6 +745,11 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware
                        ModelState modelState = mLoadedModels.get(modelHandle);
                        if (event.status != RecognitionStatus.FORCED) {
                            modelState.activityState = 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();
                        }
                    }
                }
@@ -744,6 +774,11 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware
                        ModelState modelState = mLoadedModels.get(modelHandle);
                        if (event.common.status != RecognitionStatus.FORCED) {
                            modelState.activityState = 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();
                        }
                    }
                }