Merge changes from topic "hotword_qpr" into tm-qpr-dev

* changes:
  Revert "Revert "Refactor ProximityUpdateCallbackInternal to inte..."
  Revert^2 "Add proximity state to the HotwordDetectedResult"
This commit is contained in:
Daniel Kim
2022-08-20 01:30:46 +00:00
committed by Android (Google) Code Review
4 changed files with 95 additions and 10 deletions

View File

@@ -83,11 +83,11 @@ public abstract class AttentionManagerInternal {
} }
/** Internal interface for proximity callback. */ /** Internal interface for proximity callback. */
public abstract static class ProximityUpdateCallbackInternal { public interface ProximityUpdateCallbackInternal {
/** /**
* @param distance the estimated distance of the user (in meter) * @param distance the estimated distance of the user (in meter)
* The distance will be PROXIMITY_UNKNOWN if the proximity sensing was inconclusive. * The distance will be PROXIMITY_UNKNOWN if the proximity sensing was inconclusive.
*/ */
public abstract void onProximityUpdate(double distance); void onProximityUpdate(double distance);
} }
} }

View File

@@ -95,6 +95,16 @@ public final class HotwordDetectedResult implements Parcelable {
/** Limits the max value for the triggered audio channel. */ /** Limits the max value for the triggered audio channel. */
private static final int LIMIT_AUDIO_CHANNEL_MAX_VALUE = 63; private static final int LIMIT_AUDIO_CHANNEL_MAX_VALUE = 63;
/**
* The bundle key for proximity value
*
* TODO(b/238896013): Move the proximity logic out of bundle to proper API.
*
* @hide
*/
public static final String EXTRA_PROXIMITY_METERS =
"android.service.voice.extra.PROXIMITY_METERS";
/** Confidence level in the trigger outcome. */ /** Confidence level in the trigger outcome. */
@HotwordConfidenceLevelValue @HotwordConfidenceLevelValue
private final int mConfidenceLevel; private final int mConfidenceLevel;
@@ -197,6 +207,14 @@ public final class HotwordDetectedResult implements Parcelable {
* <p>The use of this method is discouraged, and support for it will be removed in future * <p>The use of this method is discouraged, and support for it will be removed in future
* versions of Android. * versions of Android.
* *
* <p>After the trigger happens, a special case of proximity-related extra, with the key of
* 'android.service.voice.extra.PROXIMITY_METERS' and the value of distance in meters (double),
* will be stored to enable proximity logic. The proximity meters is provided by the system,
* on devices that support detecting proximity of nearby users, to help disambiguate which
* nearby device should respond. When the proximity is unknown, the proximity value will not
* be stored. This mapping will be excluded from the max bundle size calculation because this
* mapping is included after the result is returned from the hotword detector service.
*
* <p>This is a PersistableBundle so it doesn't allow any remotable objects or other contents * <p>This is a PersistableBundle so it doesn't allow any remotable objects or other contents
* that can be used to communicate with other processes. * that can be used to communicate with other processes.
*/ */
@@ -315,8 +333,23 @@ public final class HotwordDetectedResult implements Parcelable {
"audioChannel"); "audioChannel");
} }
if (!mExtras.isEmpty()) { if (!mExtras.isEmpty()) {
Preconditions.checkArgumentInRange(getParcelableSize(mExtras), 0, getMaxBundleSize(), // Remove the proximity key from the bundle before checking the bundle size. The
"extras"); // proximity value is added after the privileged module and can avoid the
// maxBundleSize limitation.
if (mExtras.containsKey(EXTRA_PROXIMITY_METERS)) {
double proximityMeters = mExtras.getDouble(EXTRA_PROXIMITY_METERS);
mExtras.remove(EXTRA_PROXIMITY_METERS);
// Skip checking parcelable size if the new bundle size is 0. Newly empty bundle
// has parcelable size of 4, but the default bundle has parcelable size of 0.
if (mExtras.size() > 0) {
Preconditions.checkArgumentInRange(getParcelableSize(mExtras), 0,
getMaxBundleSize(), "extras");
}
mExtras.putDouble(EXTRA_PROXIMITY_METERS, proximityMeters);
} else {
Preconditions.checkArgumentInRange(getParcelableSize(mExtras), 0,
getMaxBundleSize(), "extras");
}
} }
} }
@@ -513,6 +546,14 @@ public final class HotwordDetectedResult implements Parcelable {
* <p>The use of this method is discouraged, and support for it will be removed in future * <p>The use of this method is discouraged, and support for it will be removed in future
* versions of Android. * versions of Android.
* *
* <p>After the trigger happens, a special case of proximity-related extra, with the key of
* 'android.service.voice.extra.PROXIMITY_METERS' and the value of distance in meters (double),
* will be stored to enable proximity logic. The proximity meters is provided by the system,
* on devices that support detecting proximity of nearby users, to help disambiguate which
* nearby device should respond. When the proximity is unknown, the proximity value will not
* be stored. This mapping will be excluded from the max bundle size calculation because this
* mapping is included after the result is returned from the hotword detector service.
*
* <p>This is a PersistableBundle so it doesn't allow any remotable objects or other contents * <p>This is a PersistableBundle so it doesn't allow any remotable objects or other contents
* that can be used to communicate with other processes. * that can be used to communicate with other processes.
*/ */
@@ -813,6 +854,14 @@ public final class HotwordDetectedResult implements Parcelable {
* <p>The use of this method is discouraged, and support for it will be removed in future * <p>The use of this method is discouraged, and support for it will be removed in future
* versions of Android. * versions of Android.
* *
* <p>After the trigger happens, a special case of proximity-related extra, with the key of
* 'android.service.voice.extra.PROXIMITY_METERS' and the value of distance in meters (double),
* will be stored to enable proximity logic. The proximity meters is provided by the system,
* on devices that support detecting proximity of nearby users, to help disambiguate which
* nearby device should respond. When the proximity is unknown, the proximity value will not
* be stored. This mapping will be excluded from the max bundle size calculation because this
* mapping is included after the result is returned from the hotword detector service.
*
* <p>This is a PersistableBundle so it doesn't allow any remotable objects or other contents * <p>This is a PersistableBundle so it doesn't allow any remotable objects or other contents
* that can be used to communicate with other processes. * that can be used to communicate with other processes.
*/ */
@@ -882,10 +931,10 @@ public final class HotwordDetectedResult implements Parcelable {
} }
@DataClass.Generated( @DataClass.Generated(
time = 1625541522353L, time = 1658357814396L,
codegenVersion = "1.0.23", codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/service/voice/HotwordDetectedResult.java", sourceFile = "frameworks/base/core/java/android/service/voice/HotwordDetectedResult.java",
inputSignatures = "public static final int CONFIDENCE_LEVEL_NONE\npublic static final int CONFIDENCE_LEVEL_LOW\npublic static final int CONFIDENCE_LEVEL_LOW_MEDIUM\npublic static final int CONFIDENCE_LEVEL_MEDIUM\npublic static final int CONFIDENCE_LEVEL_MEDIUM_HIGH\npublic static final int CONFIDENCE_LEVEL_HIGH\npublic static final int CONFIDENCE_LEVEL_VERY_HIGH\npublic static final int HOTWORD_OFFSET_UNSET\npublic static final int AUDIO_CHANNEL_UNSET\nprivate static final int LIMIT_HOTWORD_OFFSET_MAX_VALUE\nprivate static final int LIMIT_AUDIO_CHANNEL_MAX_VALUE\nprivate final @android.service.voice.HotwordDetectedResult.HotwordConfidenceLevelValue int mConfidenceLevel\nprivate @android.annotation.Nullable android.media.MediaSyncEvent mMediaSyncEvent\nprivate int mHotwordOffsetMillis\nprivate int mHotwordDurationMillis\nprivate int mAudioChannel\nprivate boolean mHotwordDetectionPersonalized\nprivate final int mScore\nprivate final int mPersonalizedScore\nprivate final int mHotwordPhraseId\nprivate final @android.annotation.NonNull android.os.PersistableBundle mExtras\nprivate static int sMaxBundleSize\nprivate static int defaultConfidenceLevel()\nprivate static int defaultScore()\nprivate static int defaultPersonalizedScore()\npublic static int getMaxScore()\nprivate static int defaultHotwordPhraseId()\npublic static int getMaxHotwordPhraseId()\nprivate static android.os.PersistableBundle defaultExtras()\npublic static int getMaxBundleSize()\npublic @android.annotation.Nullable android.media.MediaSyncEvent getMediaSyncEvent()\npublic static int getParcelableSize(android.os.Parcelable)\npublic static int getUsageSize(android.service.voice.HotwordDetectedResult)\nprivate static int bitCount(long)\nprivate void onConstructed()\nclass HotwordDetectedResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)") inputSignatures = "public static final int CONFIDENCE_LEVEL_NONE\npublic static final int CONFIDENCE_LEVEL_LOW\npublic static final int CONFIDENCE_LEVEL_LOW_MEDIUM\npublic static final int CONFIDENCE_LEVEL_MEDIUM\npublic static final int CONFIDENCE_LEVEL_MEDIUM_HIGH\npublic static final int CONFIDENCE_LEVEL_HIGH\npublic static final int CONFIDENCE_LEVEL_VERY_HIGH\npublic static final int HOTWORD_OFFSET_UNSET\npublic static final int AUDIO_CHANNEL_UNSET\nprivate static final int LIMIT_HOTWORD_OFFSET_MAX_VALUE\nprivate static final int LIMIT_AUDIO_CHANNEL_MAX_VALUE\npublic static final java.lang.String EXTRA_PROXIMITY_METERS\nprivate final @android.service.voice.HotwordDetectedResult.HotwordConfidenceLevelValue int mConfidenceLevel\nprivate @android.annotation.Nullable android.media.MediaSyncEvent mMediaSyncEvent\nprivate int mHotwordOffsetMillis\nprivate int mHotwordDurationMillis\nprivate int mAudioChannel\nprivate boolean mHotwordDetectionPersonalized\nprivate final int mScore\nprivate final int mPersonalizedScore\nprivate final int mHotwordPhraseId\nprivate final @android.annotation.NonNull android.os.PersistableBundle mExtras\nprivate static int sMaxBundleSize\nprivate static int defaultConfidenceLevel()\nprivate static int defaultScore()\nprivate static int defaultPersonalizedScore()\npublic static int getMaxScore()\nprivate static int defaultHotwordPhraseId()\npublic static int getMaxHotwordPhraseId()\nprivate static android.os.PersistableBundle defaultExtras()\npublic static int getMaxBundleSize()\npublic @android.annotation.Nullable android.media.MediaSyncEvent getMediaSyncEvent()\npublic static int getParcelableSize(android.os.Parcelable)\npublic static int getUsageSize(android.service.voice.HotwordDetectedResult)\nprivate static int bitCount(long)\nprivate void onConstructed()\nclass HotwordDetectedResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
@Deprecated @Deprecated
private void __metadata() {} private void __metadata() {}

View File

@@ -343,6 +343,9 @@ public class AttentionManagerService extends SystemService {
* *
* Calling this multiple times for duplicate requests will be no-ops, returning true. * Calling this multiple times for duplicate requests will be no-ops, returning true.
* *
* TODO(b/239130847): Maintain the proximity state in AttentionManagerService and change this
* to a polling API.
*
* @return {@code true} if the framework was able to dispatch the request * @return {@code true} if the framework was able to dispatch the request
*/ */
@VisibleForTesting @VisibleForTesting
@@ -853,9 +856,6 @@ public class AttentionManagerService extends SystemService {
@GuardedBy("mLock") @GuardedBy("mLock")
private void cancelAndUnbindLocked() { private void cancelAndUnbindLocked() {
synchronized (mLock) { synchronized (mLock) {
if (mCurrentAttentionCheck == null && mCurrentProximityUpdate == null) {
return;
}
if (mCurrentAttentionCheck != null) { if (mCurrentAttentionCheck != null) {
cancel(); cancel();
} }
@@ -937,7 +937,7 @@ public class AttentionManagerService extends SystemService {
} }
} }
class TestableProximityUpdateCallbackInternal extends ProximityUpdateCallbackInternal { class TestableProximityUpdateCallbackInternal implements ProximityUpdateCallbackInternal {
private double mLastCallbackCode = PROXIMITY_UNKNOWN; private double mLastCallbackCode = PROXIMITY_UNKNOWN;
@Override @Override
@@ -1069,6 +1069,7 @@ public class AttentionManagerService extends SystemService {
private void resetStates() { private void resetStates() {
synchronized (mLock) { synchronized (mLock) {
mCurrentProximityUpdate = null; mCurrentProximityUpdate = null;
cancelAndUnbindLocked();
} }
mComponentName = resolveAttentionService(mContext); mComponentName = resolveAttentionService(mContext);
} }

View File

@@ -18,6 +18,8 @@ package com.android.server.voiceinteraction;
import static android.Manifest.permission.CAPTURE_AUDIO_HOTWORD; import static android.Manifest.permission.CAPTURE_AUDIO_HOTWORD;
import static android.Manifest.permission.RECORD_AUDIO; import static android.Manifest.permission.RECORD_AUDIO;
import static android.service.attention.AttentionService.PROXIMITY_UNKNOWN;
import static android.service.voice.HotwordDetectedResult.EXTRA_PROXIMITY_METERS;
import static android.service.voice.HotwordDetectionService.AUDIO_SOURCE_EXTERNAL; import static android.service.voice.HotwordDetectionService.AUDIO_SOURCE_EXTERNAL;
import static android.service.voice.HotwordDetectionService.AUDIO_SOURCE_MICROPHONE; import static android.service.voice.HotwordDetectionService.AUDIO_SOURCE_MICROPHONE;
import static android.service.voice.HotwordDetectionService.INITIALIZATION_STATUS_SUCCESS; import static android.service.voice.HotwordDetectionService.INITIALIZATION_STATUS_SUCCESS;
@@ -56,6 +58,7 @@ import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPH
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.attention.AttentionManagerInternal;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.ContentCaptureOptions; import android.content.ContentCaptureOptions;
import android.content.Context; import android.content.Context;
@@ -182,6 +185,12 @@ final class HotwordDetectionConnection {
final int mUser; final int mUser;
final Context mContext; final Context mContext;
@Nullable final AttentionManagerInternal mAttentionManagerInternal;
final AttentionManagerInternal.ProximityUpdateCallbackInternal mProximityCallbackInternal =
this::setProximityMeters;
volatile HotwordDetectionServiceIdentity mIdentity; volatile HotwordDetectionServiceIdentity mIdentity;
private IMicrophoneHotwordDetectionVoiceInteractionCallback mSoftwareCallback; private IMicrophoneHotwordDetectionVoiceInteractionCallback mSoftwareCallback;
private Instant mLastRestartInstant; private Instant mLastRestartInstant;
@@ -202,6 +211,8 @@ final class HotwordDetectionConnection {
private @NonNull ServiceConnection mRemoteHotwordDetectionService; private @NonNull ServiceConnection mRemoteHotwordDetectionService;
private IBinder mAudioFlinger; private IBinder mAudioFlinger;
private boolean mDebugHotwordLogging = false; private boolean mDebugHotwordLogging = false;
@GuardedBy("mLock")
private double mProximityMeters = PROXIMITY_UNKNOWN;
HotwordDetectionConnection(Object lock, Context context, int voiceInteractionServiceUid, HotwordDetectionConnection(Object lock, Context context, int voiceInteractionServiceUid,
Identity voiceInteractorIdentity, ComponentName serviceName, int userId, Identity voiceInteractorIdentity, ComponentName serviceName, int userId,
@@ -229,6 +240,10 @@ final class HotwordDetectionConnection {
mServiceConnectionFactory = new ServiceConnectionFactory(intent, bindInstantServiceAllowed); mServiceConnectionFactory = new ServiceConnectionFactory(intent, bindInstantServiceAllowed);
mRemoteHotwordDetectionService = mServiceConnectionFactory.createLocked(); mRemoteHotwordDetectionService = mServiceConnectionFactory.createLocked();
mAttentionManagerInternal = LocalServices.getService(AttentionManagerInternal.class);
if (mAttentionManagerInternal != null) {
mAttentionManagerInternal.onStartProximityUpdates(mProximityCallbackInternal);
}
mLastRestartInstant = Instant.now(); mLastRestartInstant = Instant.now();
updateStateAfterProcessStart(options, sharedMemory); updateStateAfterProcessStart(options, sharedMemory);
@@ -393,6 +408,9 @@ final class HotwordDetectionConnection {
if (mAudioFlinger != null) { if (mAudioFlinger != null) {
mAudioFlinger.unlinkToDeath(mAudioServerDeathRecipient, /* flags= */ 0); mAudioFlinger.unlinkToDeath(mAudioServerDeathRecipient, /* flags= */ 0);
} }
if (mAttentionManagerInternal != null) {
mAttentionManagerInternal.onStopProximityUpdates(mProximityCallbackInternal);
}
} }
void updateStateLocked(PersistableBundle options, SharedMemory sharedMemory) { void updateStateLocked(PersistableBundle options, SharedMemory sharedMemory) {
@@ -460,6 +478,7 @@ final class HotwordDetectionConnection {
mSoftwareCallback.onError(); mSoftwareCallback.onError();
return; return;
} }
saveProximityMetersToBundle(result);
mSoftwareCallback.onDetected(result, null, null); mSoftwareCallback.onDetected(result, null, null);
if (result != null) { if (result != null) {
Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(result) Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(result)
@@ -564,6 +583,7 @@ final class HotwordDetectionConnection {
externalCallback.onError(CALLBACK_ONDETECTED_GOT_SECURITY_EXCEPTION); externalCallback.onError(CALLBACK_ONDETECTED_GOT_SECURITY_EXCEPTION);
return; return;
} }
saveProximityMetersToBundle(result);
externalCallback.onKeyphraseDetected(recognitionEvent, result); externalCallback.onKeyphraseDetected(recognitionEvent, result);
if (result != null) { if (result != null) {
Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(result) Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(result)
@@ -643,6 +663,7 @@ final class HotwordDetectionConnection {
externalCallback.onError(CALLBACK_ONDETECTED_GOT_SECURITY_EXCEPTION); externalCallback.onError(CALLBACK_ONDETECTED_GOT_SECURITY_EXCEPTION);
return; return;
} }
saveProximityMetersToBundle(result);
externalCallback.onKeyphraseDetected(recognitionEvent, result); externalCallback.onKeyphraseDetected(recognitionEvent, result);
if (result != null) { if (result != null) {
Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(result) Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(result)
@@ -1191,6 +1212,20 @@ final class HotwordDetectionConnection {
}); });
} }
private void saveProximityMetersToBundle(HotwordDetectedResult result) {
synchronized (mLock) {
if (result != null && mProximityMeters != PROXIMITY_UNKNOWN) {
result.getExtras().putDouble(EXTRA_PROXIMITY_METERS, mProximityMeters);
}
}
}
private void setProximityMeters(double proximityMeters) {
synchronized (mLock) {
mProximityMeters = proximityMeters;
}
}
private static void bestEffortClose(Closeable... closeables) { private static void bestEffortClose(Closeable... closeables) {
for (Closeable closeable : closeables) { for (Closeable closeable : closeables) {
bestEffortClose(closeable); bestEffortClose(closeable);