RESTRICT AUTOMERGE Restart recognition when failing to deliver event am: 7769bbdaaa

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15337429

Change-Id: Ia9240317af16ec9eadce4c94db2d8c8858391c6d
This commit is contained in:
Ytai Ben-Tsvi
2021-07-22 08:08:25 +00:00
committed by Automerger Merge Worker
2 changed files with 45 additions and 13 deletions

View File

@@ -133,13 +133,8 @@ public class SoundTriggerMiddlewarePermission implements ISoundTriggerMiddleware
* Throws a {@link SecurityException} iff the originator has permission to receive data. * Throws a {@link SecurityException} iff the originator has permission to receive data.
*/ */
void enforcePermissionsForDataDelivery(@NonNull Identity identity, @NonNull String reason) { void enforcePermissionsForDataDelivery(@NonNull Identity identity, @NonNull String reason) {
// TODO(b/186164881): remove enforcePermissionForDataDelivery(mContext, identity, RECORD_AUDIO,
// START TEMP HACK reason);
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, CAPTURE_AUDIO_HOTWORD, enforcePermissionForDataDelivery(mContext, identity, CAPTURE_AUDIO_HOTWORD,
reason); reason);
} }
@@ -167,8 +162,8 @@ public class SoundTriggerMiddlewarePermission implements ISoundTriggerMiddleware
/** /**
* Throws a {@link SecurityException} if originator permanently doesn't have the given * Throws a {@link SecurityException} if originator permanently doesn't have the given
* permission, or a {@link ServiceSpecificException} with a {@link * permission.
* Status#TEMPORARY_PERMISSION_DENIED} if caller originator doesn't have the given permission. * Soft (temporary) denials are considered OK for preflight purposes.
* *
* @param context A {@link Context}, used for permission checks. * @param context A {@link Context}, used for permission checks.
* @param identity The identity to check. * @param identity The identity to check.
@@ -180,15 +175,12 @@ public class SoundTriggerMiddlewarePermission implements ISoundTriggerMiddleware
permission); permission);
switch (status) { switch (status) {
case PermissionChecker.PERMISSION_GRANTED: case PermissionChecker.PERMISSION_GRANTED:
case PermissionChecker.PERMISSION_SOFT_DENIED:
return; return;
case PermissionChecker.PERMISSION_HARD_DENIED: case PermissionChecker.PERMISSION_HARD_DENIED:
throw new SecurityException( throw new SecurityException(
String.format("Failed to obtain permission %s for identity %s", permission, String.format("Failed to obtain permission %s for identity %s", permission,
ObjectPrinter.print(identity, true, 16))); 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: default:
throw new RuntimeException("Unexpected perimission check result."); throw new RuntimeException("Unexpected perimission check result.");
} }

View File

@@ -318,6 +318,8 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware
*/ */
private Map<Integer, ModelParameterRange> parameterSupport = new HashMap<>(); private Map<Integer, ModelParameterRange> parameterSupport = new HashMap<>();
private RecognitionConfig mConfig;
/** /**
* Check that the given parameter is known to be supported for this model. * 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) { void setActivityState(Activity activity) {
mActivityState.set(activity.ordinal()); 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 // 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, // the activity state may be reset outside of the lock, we set it here first,
// and reset it in case of exception. // and reset it in case of exception.
modelState.setRecognitionConfig(config);
modelState.setActivityState(ModelState.Activity.ACTIVE); modelState.setActivityState(ModelState.Activity.ACTIVE);
mDelegate.startRecognition(modelHandle, config); mDelegate.startRecognition(modelHandle, config);
} catch (Exception e) { } 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 @Override
public void forceRecognitionEvent(int modelHandle) { public void forceRecognitionEvent(int modelHandle) {
// Input validation (always valid). // Input validation (always valid).
@@ -753,6 +785,10 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware
Log.e(TAG, "Client callback exception.", e); Log.e(TAG, "Client callback exception.", e);
if (event.status != RecognitionStatus.FORCED) { if (event.status != RecognitionStatus.FORCED) {
modelState.setActivityState(ModelState.Activity.INTERCEPTED); 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); Log.e(TAG, "Client callback exception.", e);
if (event.common.status != RecognitionStatus.FORCED) { if (event.common.status != RecognitionStatus.FORCED) {
modelState.setActivityState(ModelState.Activity.INTERCEPTED); 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();
} }
} }
} }