Merge "Restart recognition when failing to deliver event"

This commit is contained in:
Eric Laurent
2021-07-22 07:48:59 +00:00
committed by Android (Google) Code Review
2 changed files with 40 additions and 13 deletions

View File

@@ -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.");
}

View File

@@ -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();
}
}
}