Loading services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectorSession.java→services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java +27 −21 Original line number Diff line number Diff line Loading @@ -93,21 +93,27 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; /** * A class that provides trusted hotword detector to communicate with the {@link * HotwordDetectionService}. * A class that provides sandboxed detector to communicate with the {@link * HotwordDetectionService} and {@link VisualQueryDetectionService}. * * This class provides the methods to do initialization with the {@link HotwordDetectionService} * and handle external source detection. It also provides the methods to check if we can egress * the data from the {@link HotwordDetectionService}. * Trusted hotword detectors such as {@link SoftwareHotwordDetector} and * {@link AlwaysOnHotwordDetector} will leverage this class to communitcate with * {@link HotwordDetectionService}; similarly, {@link VisualQueryDetector} will communicate with * {@link VisualQueryDetectionService}. * * This class provides the methods to do initialization with the {@link HotwordDetectionService} and * {@link VisualQueryDetectionService} handles external source detection for * {@link HotwordDetectionService}. It also provides the methods to check if we can egress the data * from the {@link HotwordDetectionService} and {@link VisualQueryDetectionService}. * * The subclass should override the {@link #informRestartProcessLocked()} to handle the trusted * process restart. */ abstract class HotwordDetectorSession { private static final String TAG = "HotwordDetectorSession"; abstract class DetectorSession { private static final String TAG = "DetectorSession"; static final boolean DEBUG = false; private static final String OP_MESSAGE = private static final String HOTWORD_DETECTION_OP_MESSAGE = "Providing hotword detection result to VoiceInteractionService"; // The error codes are used for onError callback Loading Loading @@ -173,7 +179,7 @@ abstract class HotwordDetectorSession { @GuardedBy("mLock") ParcelFileDescriptor mCurrentAudioSink; @GuardedBy("mLock") @NonNull HotwordDetectionConnection.ServiceConnection mRemoteHotwordDetectionService; @NonNull HotwordDetectionConnection.ServiceConnection mRemoteDetectionService; boolean mDebugHotwordLogging = false; @GuardedBy("mLock") private double mProximityMeters = PROXIMITY_UNKNOWN; Loading @@ -185,13 +191,13 @@ abstract class HotwordDetectorSession { boolean mPerformingExternalSourceHotwordDetection; @NonNull final IBinder mToken; HotwordDetectorSession( @NonNull HotwordDetectionConnection.ServiceConnection remoteHotwordDetectionService, DetectorSession( @NonNull HotwordDetectionConnection.ServiceConnection remoteDetectionService, @NonNull Object lock, @NonNull Context context, @NonNull IBinder token, @NonNull IHotwordRecognitionStatusCallback callback, int voiceInteractionServiceUid, Identity voiceInteractorIdentity, @NonNull ScheduledExecutorService scheduledExecutorService, boolean logging) { mRemoteHotwordDetectionService = remoteHotwordDetectionService; mRemoteDetectionService = remoteDetectionService; mLock = lock; mContext = context; mToken = token; Loading Loading @@ -219,7 +225,7 @@ abstract class HotwordDetectorSession { if (DEBUG) { Slog.d(TAG, "updateStateAfterProcessStartLocked"); } AndroidFuture<Void> voidFuture = mRemoteHotwordDetectionService.postAsync(service -> { AndroidFuture<Void> voidFuture = mRemoteDetectionService.postAsync(service -> { AndroidFuture<Void> future = new AndroidFuture<>(); IRemoteCallback statusCallback = new IRemoteCallback.Stub() { @Override Loading Loading @@ -319,7 +325,7 @@ abstract class HotwordDetectorSession { Slog.v(TAG, "call updateStateAfterProcessStartLocked"); updateStateAfterProcessStartLocked(options, sharedMemory); } else { mRemoteHotwordDetectionService.run( mRemoteDetectionService.run( service -> service.updateState(options, sharedMemory, /* callback= */ null)); } } Loading Loading @@ -407,7 +413,7 @@ abstract class HotwordDetectorSession { // TODO: handle cancellations well // TODO: what if we cancelled and started a new one? mRemoteHotwordDetectionService.run( mRemoteDetectionService.run( service -> { service.detectFromMicrophoneSource( serviceAudioSource, Loading Loading @@ -512,7 +518,7 @@ abstract class HotwordDetectorSession { void destroyLocked() { mDestroyed = true; mDebugHotwordLogging = false; mRemoteHotwordDetectionService = null; mRemoteDetectionService = null; if (mAttentionManagerInternal != null) { mAttentionManagerInternal.onStopProximityUpdates(mProximityCallbackInternal); } Loading @@ -524,9 +530,9 @@ abstract class HotwordDetectorSession { } @SuppressWarnings("GuardedBy") void updateRemoteHotwordDetectionServiceLocked( @NonNull HotwordDetectionConnection.ServiceConnection remoteHotwordDetectionService) { mRemoteHotwordDetectionService = remoteHotwordDetectionService; void updateRemoteSandboxedDetectionServiceLocked( @NonNull HotwordDetectionConnection.ServiceConnection remoteDetectionService) { mRemoteDetectionService = remoteDetectionService; } void reportErrorLocked(int status) { Loading Loading @@ -628,9 +634,9 @@ abstract class HotwordDetectorSession { int hotwordOp = AppOpsManager.strOpToOp(AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD); mAppOpsManager.noteOpNoThrow(hotwordOp, mVoiceInteractorIdentity.uid, mVoiceInteractorIdentity.packageName, mVoiceInteractorIdentity.attributionTag, OP_MESSAGE); mVoiceInteractorIdentity.attributionTag, HOTWORD_DETECTION_OP_MESSAGE); enforcePermissionForDataDelivery(mContext, mVoiceInteractorIdentity, CAPTURE_AUDIO_HOTWORD, OP_MESSAGE); CAPTURE_AUDIO_HOTWORD, HOTWORD_DETECTION_OP_MESSAGE); } }); } Loading services/voiceinteraction/java/com/android/server/voiceinteraction/DspTrustedHotwordDetectorSession.java +2 −3 Original line number Diff line number Diff line Loading @@ -32,7 +32,6 @@ import android.os.IBinder; import android.os.PersistableBundle; import android.os.RemoteException; import android.os.SharedMemory; import android.service.voice.AlwaysOnHotwordDetector; import android.service.voice.HotwordDetectedResult; import android.service.voice.HotwordDetectionService; import android.service.voice.HotwordDetector; Loading @@ -59,7 +58,7 @@ import java.util.concurrent.atomic.AtomicBoolean; * {@link android.service.voice.VoiceInteractionService#createAlwaysOnHotwordDetector(String, * Locale, PersistableBundle, SharedMemory, AlwaysOnHotwordDetector.Callback)}. */ final class DspTrustedHotwordDetectorSession extends HotwordDetectorSession { final class DspTrustedHotwordDetectorSession extends DetectorSession { private static final String TAG = "DspTrustedHotwordDetectorSession"; // The validation timeout value is 3 seconds for onDetect of DSP trigger event. Loading Loading @@ -182,7 +181,7 @@ final class DspTrustedHotwordDetectorSession extends HotwordDetectorSession { }; mValidatingDspTrigger = true; mRemoteHotwordDetectionService.run(service -> { mRemoteDetectionService.run(service -> { // We use the VALIDATION_TIMEOUT_MILLIS to inform that the client needs to invoke // the callback before timeout value. In order to reduce the latency impact between // server side and client side, we need to use another timeout value Loading services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java +48 −45 Original line number Diff line number Diff line Loading @@ -89,7 +89,7 @@ final class HotwordDetectionConnection { Executors.newSingleThreadScheduledExecutor(); @Nullable private final ScheduledFuture<?> mCancellationTaskFuture; private final IBinder.DeathRecipient mAudioServerDeathRecipient = this::audioServerDied; @NonNull private final ServiceConnectionFactory mServiceConnectionFactory; @NonNull private final ServiceConnectionFactory mHotwordDetectionServiceConnectionFactory; private final int mDetectorType; /** * Time after which each HotwordDetectionService process is stopped and replaced by a new one. Loading @@ -99,7 +99,7 @@ final class HotwordDetectionConnection { final Object mLock; final int mVoiceInteractionServiceUid; final ComponentName mDetectionComponentName; final ComponentName mHotwordDetectionComponentName; final int mUser; final Context mContext; volatile HotwordDetectionServiceIdentity mIdentity; Loading @@ -122,27 +122,30 @@ final class HotwordDetectionConnection { * to record the detectors. */ @GuardedBy("mLock") private final SparseArray<HotwordDetectorSession> mHotwordDetectorSessions = private final SparseArray<DetectorSession> mDetectorSessions = new SparseArray<>(); HotwordDetectionConnection(Object lock, Context context, int voiceInteractionServiceUid, Identity voiceInteractorIdentity, ComponentName serviceName, int userId, Identity voiceInteractorIdentity, ComponentName hotwordDetectionServiceName, int userId, boolean bindInstantServiceAllowed, int detectorType) { mLock = lock; mContext = context; mVoiceInteractionServiceUid = voiceInteractionServiceUid; mVoiceInteractorIdentity = voiceInteractorIdentity; mDetectionComponentName = serviceName; mHotwordDetectionComponentName = hotwordDetectionServiceName; mUser = userId; mDetectorType = detectorType; mReStartPeriodSeconds = DeviceConfig.getInt(DeviceConfig.NAMESPACE_VOICE_INTERACTION, KEY_RESTART_PERIOD_IN_SECONDS, 0); final Intent intent = new Intent(HotwordDetectionService.SERVICE_INTERFACE); intent.setComponent(mDetectionComponentName); final Intent hotwordDetectionServiceIntent = new Intent(HotwordDetectionService.SERVICE_INTERFACE); hotwordDetectionServiceIntent.setComponent(mHotwordDetectionComponentName); initAudioFlingerLocked(); mServiceConnectionFactory = new ServiceConnectionFactory(intent, bindInstantServiceAllowed); mRemoteHotwordDetectionService = mServiceConnectionFactory.createLocked(); mHotwordDetectionServiceConnectionFactory = new ServiceConnectionFactory(hotwordDetectionServiceIntent, bindInstantServiceAllowed); mRemoteHotwordDetectionService = mHotwordDetectionServiceConnectionFactory.createLocked(); mLastRestartInstant = Instant.now(); if (mReStartPeriodSeconds <= 0) { Loading Loading @@ -176,8 +179,8 @@ final class HotwordDetectionConnection { try { mAudioFlinger.linkToDeath(mAudioServerDeathRecipient, /* flags= */ 0); } catch (RemoteException e) { Slog.w(TAG, "Audio server died before we registered a DeathRecipient; retrying init.", e); Slog.w(TAG, "Audio server died before we registered a DeathRecipient; " + "retrying init.", e); initAudioFlingerLocked(); } } Loading @@ -200,10 +203,10 @@ final class HotwordDetectionConnection { void cancelLocked() { Slog.v(TAG, "cancelLocked"); clearDebugHotwordLoggingTimeoutLocked(); runForEachHotwordDetectorSessionLocked((session) -> { runForEachDetectorSessionLocked((session) -> { session.destroyLocked(); }); mHotwordDetectorSessions.clear(); mDetectorSessions.clear(); mDebugHotwordLogging = false; mRemoteHotwordDetectionService.unbind(); LocalServices.getService(PermissionManagerServiceInternal.class) Loading @@ -223,7 +226,7 @@ final class HotwordDetectionConnection { @SuppressWarnings("GuardedBy") void updateStateLocked(PersistableBundle options, SharedMemory sharedMemory, @NonNull IBinder token) { final HotwordDetectorSession session = getDetectorSessionByTokenLocked(token); final DetectorSession session = getDetectorSessionByTokenLocked(token); if (session == null) { Slog.v(TAG, "Not found the detector by token"); return; Loading Loading @@ -259,7 +262,7 @@ final class HotwordDetectionConnection { if (DEBUG) { Slog.d(TAG, "startListeningFromExternalSourceLocked"); } final HotwordDetectorSession session = getDetectorSessionByTokenLocked(token); final DetectorSession session = getDetectorSessionByTokenLocked(token); if (session == null) { Slog.v(TAG, "Not found the detector by token"); return; Loading Loading @@ -321,7 +324,7 @@ final class HotwordDetectionConnection { Slog.v(TAG, "setDebugHotwordLoggingLocked: " + logging); clearDebugHotwordLoggingTimeoutLocked(); mDebugHotwordLogging = logging; runForEachHotwordDetectorSessionLocked((session) -> { runForEachDetectorSessionLocked((session) -> { session.setDebugHotwordLoggingLocked(logging); }); Loading @@ -331,7 +334,7 @@ final class HotwordDetectionConnection { Slog.v(TAG, "Timeout to reset mDebugHotwordLogging to false"); synchronized (mLock) { mDebugHotwordLogging = false; runForEachHotwordDetectorSessionLocked((session) -> { runForEachDetectorSessionLocked((session) -> { session.setDebugHotwordLoggingLocked(false); }); } Loading @@ -350,24 +353,24 @@ final class HotwordDetectionConnection { private void restartProcessLocked() { // TODO(b/244598068): Check HotwordAudioStreamManager first Slog.v(TAG, "Restarting hotword detection process"); ServiceConnection oldConnection = mRemoteHotwordDetectionService; ServiceConnection oldHotwordConnection = mRemoteHotwordDetectionService; HotwordDetectionServiceIdentity previousIdentity = mIdentity; mLastRestartInstant = Instant.now(); // Recreate connection to reset the cache. mRemoteHotwordDetectionService = mServiceConnectionFactory.createLocked(); mRemoteHotwordDetectionService = mHotwordDetectionServiceConnectionFactory.createLocked(); Slog.v(TAG, "Started the new process, dispatching processRestarted to detector"); runForEachHotwordDetectorSessionLocked((session) -> { session.updateRemoteHotwordDetectionServiceLocked(mRemoteHotwordDetectionService); runForEachDetectorSessionLocked((session) -> { session.updateRemoteSandboxedDetectionServiceLocked(mRemoteHotwordDetectionService); session.informRestartProcessLocked(); }); if (DEBUG) { Slog.i(TAG, "processRestarted is dispatched done, unbinding from the old process"); } oldConnection.ignoreConnectionStatusEvents(); oldConnection.unbind(); oldHotwordConnection.ignoreConnectionStatusEvents(); oldHotwordConnection.unbind(); if (previousIdentity != null) { removeServiceUidForAudioPolicy(previousIdentity.getIsolatedUid()); } Loading Loading @@ -437,12 +440,12 @@ final class HotwordDetectionConnection { pw.print(prefix); pw.print("mBound="); pw.println(mRemoteHotwordDetectionService.isBound()); pw.print(prefix); pw.print("mRestartCount="); pw.println(mServiceConnectionFactory.mRestartCount); pw.println(mHotwordDetectionServiceConnectionFactory.mRestartCount); pw.print(prefix); pw.print("mLastRestartInstant="); pw.println(mLastRestartInstant); pw.print(prefix); pw.print("mDetectorType="); pw.println(HotwordDetector.detectorTypeToString(mDetectorType)); pw.print(prefix); pw.println("HotwordDetectorSession(s)"); runForEachHotwordDetectorSessionLocked((session) -> { pw.print(prefix); pw.println("DetectorSession(s)"); runForEachDetectorSessionLocked((session) -> { session.dumpLocked(prefix, pw); }); } Loading Loading @@ -537,9 +540,9 @@ final class HotwordDetectionConnection { } } synchronized (HotwordDetectionConnection.this.mLock) { runForEachHotwordDetectorSessionLocked((session) -> { runForEachDetectorSessionLocked((session) -> { session.reportErrorLocked( HotwordDetectorSession.HOTWORD_DETECTION_SERVICE_DIED); DetectorSession.HOTWORD_DETECTION_SERVICE_DIED); }); } // Can improve to log exit reason if needed Loading Loading @@ -599,12 +602,12 @@ final class HotwordDetectionConnection { int detectorType) { // We only support one Dsp trusted hotword detector and one software hotword detector at // the same time, remove existing one. HotwordDetectorSession removeSession = mHotwordDetectorSessions.get(detectorType); DetectorSession removeSession = mDetectorSessions.get(detectorType); if (removeSession != null) { removeSession.destroyLocked(); mHotwordDetectorSessions.remove(detectorType); mDetectorSessions.remove(detectorType); } final HotwordDetectorSession session; final DetectorSession session; if (detectorType == HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_DSP) { session = new DspTrustedHotwordDetectorSession(mRemoteHotwordDetectionService, mLock, mContext, token, callback, mVoiceInteractionServiceUid, Loading @@ -615,30 +618,30 @@ final class HotwordDetectionConnection { mVoiceInteractionServiceUid, mVoiceInteractorIdentity, mScheduledExecutorService, mDebugHotwordLogging); } mHotwordDetectorSessions.put(detectorType, session); mDetectorSessions.put(detectorType, session); session.initialize(options, sharedMemory); } @SuppressWarnings("GuardedBy") void destroyDetectorLocked(@NonNull IBinder token) { final HotwordDetectorSession session = getDetectorSessionByTokenLocked(token); final DetectorSession session = getDetectorSessionByTokenLocked(token); if (session != null) { session.destroyLocked(); final int index = mHotwordDetectorSessions.indexOfValue(session); if (index < 0 || index > mHotwordDetectorSessions.size() - 1) { final int index = mDetectorSessions.indexOfValue(session); if (index < 0 || index > mDetectorSessions.size() - 1) { return; } mHotwordDetectorSessions.removeAt(index); mDetectorSessions.removeAt(index); } } @SuppressWarnings("GuardedBy") private HotwordDetectorSession getDetectorSessionByTokenLocked(IBinder token) { private DetectorSession getDetectorSessionByTokenLocked(IBinder token) { if (token == null) { return null; } for (int i = 0; i < mHotwordDetectorSessions.size(); i++) { final HotwordDetectorSession session = mHotwordDetectorSessions.valueAt(i); for (int i = 0; i < mDetectorSessions.size(); i++) { final DetectorSession session = mDetectorSessions.valueAt(i); if (!session.isDestroyed() && session.isSameToken(token)) { return session; } Loading @@ -648,7 +651,7 @@ final class HotwordDetectionConnection { @SuppressWarnings("GuardedBy") private DspTrustedHotwordDetectorSession getDspTrustedHotwordDetectorSessionLocked() { final HotwordDetectorSession session = mHotwordDetectorSessions.get( final DetectorSession session = mDetectorSessions.get( HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_DSP); if (session == null || session.isDestroyed()) { Slog.v(TAG, "Not found the Dsp detector"); Loading @@ -659,7 +662,7 @@ final class HotwordDetectionConnection { @SuppressWarnings("GuardedBy") private SoftwareTrustedHotwordDetectorSession getSoftwareTrustedHotwordDetectorSessionLocked() { final HotwordDetectorSession session = mHotwordDetectorSessions.get( final DetectorSession session = mDetectorSessions.get( HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_SOFTWARE); if (session == null || session.isDestroyed()) { Slog.v(TAG, "Not found the software detector"); Loading @@ -669,10 +672,10 @@ final class HotwordDetectionConnection { } @SuppressWarnings("GuardedBy") private void runForEachHotwordDetectorSessionLocked( @NonNull Consumer<HotwordDetectorSession> action) { for (int i = 0; i < mHotwordDetectorSessions.size(); i++) { HotwordDetectorSession session = mHotwordDetectorSessions.valueAt(i); private void runForEachDetectorSessionLocked( @NonNull Consumer<DetectorSession> action) { for (int i = 0; i < mDetectorSessions.size(); i++) { DetectorSession session = mDetectorSessions.valueAt(i); action.accept(session); } } Loading services/voiceinteraction/java/com/android/server/voiceinteraction/SoftwareTrustedHotwordDetectorSession.java +3 −3 Original line number Diff line number Diff line Loading @@ -55,7 +55,7 @@ import java.util.concurrent.ScheduledExecutorService; * {@link android.service.voice.VoiceInteractionService#createHotwordDetector(PersistableBundle, * SharedMemory, HotwordDetector.Callback)}. */ final class SoftwareTrustedHotwordDetectorSession extends HotwordDetectorSession { final class SoftwareTrustedHotwordDetectorSession extends DetectorSession { private static final String TAG = "SoftwareTrustedHotwordDetectorSession"; private IMicrophoneHotwordDetectionVoiceInteractionCallback mSoftwareCallback; Loading Loading @@ -155,7 +155,7 @@ final class SoftwareTrustedHotwordDetectorSession extends HotwordDetectorSession } }; mRemoteHotwordDetectionService.run( mRemoteDetectionService.run( service -> service.detectFromMicrophoneSource( null, AUDIO_SOURCE_MICROPHONE, Loading @@ -179,7 +179,7 @@ final class SoftwareTrustedHotwordDetectorSession extends HotwordDetectorSession } mPerformingSoftwareHotwordDetection = false; mRemoteHotwordDetectionService.run(ISandboxedDetectionService::stopDetection); mRemoteDetectionService.run(ISandboxedDetectionService::stopDetection); closeExternalAudioStreamLocked("stopping requested"); } Loading Loading
services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectorSession.java→services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java +27 −21 Original line number Diff line number Diff line Loading @@ -93,21 +93,27 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; /** * A class that provides trusted hotword detector to communicate with the {@link * HotwordDetectionService}. * A class that provides sandboxed detector to communicate with the {@link * HotwordDetectionService} and {@link VisualQueryDetectionService}. * * This class provides the methods to do initialization with the {@link HotwordDetectionService} * and handle external source detection. It also provides the methods to check if we can egress * the data from the {@link HotwordDetectionService}. * Trusted hotword detectors such as {@link SoftwareHotwordDetector} and * {@link AlwaysOnHotwordDetector} will leverage this class to communitcate with * {@link HotwordDetectionService}; similarly, {@link VisualQueryDetector} will communicate with * {@link VisualQueryDetectionService}. * * This class provides the methods to do initialization with the {@link HotwordDetectionService} and * {@link VisualQueryDetectionService} handles external source detection for * {@link HotwordDetectionService}. It also provides the methods to check if we can egress the data * from the {@link HotwordDetectionService} and {@link VisualQueryDetectionService}. * * The subclass should override the {@link #informRestartProcessLocked()} to handle the trusted * process restart. */ abstract class HotwordDetectorSession { private static final String TAG = "HotwordDetectorSession"; abstract class DetectorSession { private static final String TAG = "DetectorSession"; static final boolean DEBUG = false; private static final String OP_MESSAGE = private static final String HOTWORD_DETECTION_OP_MESSAGE = "Providing hotword detection result to VoiceInteractionService"; // The error codes are used for onError callback Loading Loading @@ -173,7 +179,7 @@ abstract class HotwordDetectorSession { @GuardedBy("mLock") ParcelFileDescriptor mCurrentAudioSink; @GuardedBy("mLock") @NonNull HotwordDetectionConnection.ServiceConnection mRemoteHotwordDetectionService; @NonNull HotwordDetectionConnection.ServiceConnection mRemoteDetectionService; boolean mDebugHotwordLogging = false; @GuardedBy("mLock") private double mProximityMeters = PROXIMITY_UNKNOWN; Loading @@ -185,13 +191,13 @@ abstract class HotwordDetectorSession { boolean mPerformingExternalSourceHotwordDetection; @NonNull final IBinder mToken; HotwordDetectorSession( @NonNull HotwordDetectionConnection.ServiceConnection remoteHotwordDetectionService, DetectorSession( @NonNull HotwordDetectionConnection.ServiceConnection remoteDetectionService, @NonNull Object lock, @NonNull Context context, @NonNull IBinder token, @NonNull IHotwordRecognitionStatusCallback callback, int voiceInteractionServiceUid, Identity voiceInteractorIdentity, @NonNull ScheduledExecutorService scheduledExecutorService, boolean logging) { mRemoteHotwordDetectionService = remoteHotwordDetectionService; mRemoteDetectionService = remoteDetectionService; mLock = lock; mContext = context; mToken = token; Loading Loading @@ -219,7 +225,7 @@ abstract class HotwordDetectorSession { if (DEBUG) { Slog.d(TAG, "updateStateAfterProcessStartLocked"); } AndroidFuture<Void> voidFuture = mRemoteHotwordDetectionService.postAsync(service -> { AndroidFuture<Void> voidFuture = mRemoteDetectionService.postAsync(service -> { AndroidFuture<Void> future = new AndroidFuture<>(); IRemoteCallback statusCallback = new IRemoteCallback.Stub() { @Override Loading Loading @@ -319,7 +325,7 @@ abstract class HotwordDetectorSession { Slog.v(TAG, "call updateStateAfterProcessStartLocked"); updateStateAfterProcessStartLocked(options, sharedMemory); } else { mRemoteHotwordDetectionService.run( mRemoteDetectionService.run( service -> service.updateState(options, sharedMemory, /* callback= */ null)); } } Loading Loading @@ -407,7 +413,7 @@ abstract class HotwordDetectorSession { // TODO: handle cancellations well // TODO: what if we cancelled and started a new one? mRemoteHotwordDetectionService.run( mRemoteDetectionService.run( service -> { service.detectFromMicrophoneSource( serviceAudioSource, Loading Loading @@ -512,7 +518,7 @@ abstract class HotwordDetectorSession { void destroyLocked() { mDestroyed = true; mDebugHotwordLogging = false; mRemoteHotwordDetectionService = null; mRemoteDetectionService = null; if (mAttentionManagerInternal != null) { mAttentionManagerInternal.onStopProximityUpdates(mProximityCallbackInternal); } Loading @@ -524,9 +530,9 @@ abstract class HotwordDetectorSession { } @SuppressWarnings("GuardedBy") void updateRemoteHotwordDetectionServiceLocked( @NonNull HotwordDetectionConnection.ServiceConnection remoteHotwordDetectionService) { mRemoteHotwordDetectionService = remoteHotwordDetectionService; void updateRemoteSandboxedDetectionServiceLocked( @NonNull HotwordDetectionConnection.ServiceConnection remoteDetectionService) { mRemoteDetectionService = remoteDetectionService; } void reportErrorLocked(int status) { Loading Loading @@ -628,9 +634,9 @@ abstract class HotwordDetectorSession { int hotwordOp = AppOpsManager.strOpToOp(AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD); mAppOpsManager.noteOpNoThrow(hotwordOp, mVoiceInteractorIdentity.uid, mVoiceInteractorIdentity.packageName, mVoiceInteractorIdentity.attributionTag, OP_MESSAGE); mVoiceInteractorIdentity.attributionTag, HOTWORD_DETECTION_OP_MESSAGE); enforcePermissionForDataDelivery(mContext, mVoiceInteractorIdentity, CAPTURE_AUDIO_HOTWORD, OP_MESSAGE); CAPTURE_AUDIO_HOTWORD, HOTWORD_DETECTION_OP_MESSAGE); } }); } Loading
services/voiceinteraction/java/com/android/server/voiceinteraction/DspTrustedHotwordDetectorSession.java +2 −3 Original line number Diff line number Diff line Loading @@ -32,7 +32,6 @@ import android.os.IBinder; import android.os.PersistableBundle; import android.os.RemoteException; import android.os.SharedMemory; import android.service.voice.AlwaysOnHotwordDetector; import android.service.voice.HotwordDetectedResult; import android.service.voice.HotwordDetectionService; import android.service.voice.HotwordDetector; Loading @@ -59,7 +58,7 @@ import java.util.concurrent.atomic.AtomicBoolean; * {@link android.service.voice.VoiceInteractionService#createAlwaysOnHotwordDetector(String, * Locale, PersistableBundle, SharedMemory, AlwaysOnHotwordDetector.Callback)}. */ final class DspTrustedHotwordDetectorSession extends HotwordDetectorSession { final class DspTrustedHotwordDetectorSession extends DetectorSession { private static final String TAG = "DspTrustedHotwordDetectorSession"; // The validation timeout value is 3 seconds for onDetect of DSP trigger event. Loading Loading @@ -182,7 +181,7 @@ final class DspTrustedHotwordDetectorSession extends HotwordDetectorSession { }; mValidatingDspTrigger = true; mRemoteHotwordDetectionService.run(service -> { mRemoteDetectionService.run(service -> { // We use the VALIDATION_TIMEOUT_MILLIS to inform that the client needs to invoke // the callback before timeout value. In order to reduce the latency impact between // server side and client side, we need to use another timeout value Loading
services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java +48 −45 Original line number Diff line number Diff line Loading @@ -89,7 +89,7 @@ final class HotwordDetectionConnection { Executors.newSingleThreadScheduledExecutor(); @Nullable private final ScheduledFuture<?> mCancellationTaskFuture; private final IBinder.DeathRecipient mAudioServerDeathRecipient = this::audioServerDied; @NonNull private final ServiceConnectionFactory mServiceConnectionFactory; @NonNull private final ServiceConnectionFactory mHotwordDetectionServiceConnectionFactory; private final int mDetectorType; /** * Time after which each HotwordDetectionService process is stopped and replaced by a new one. Loading @@ -99,7 +99,7 @@ final class HotwordDetectionConnection { final Object mLock; final int mVoiceInteractionServiceUid; final ComponentName mDetectionComponentName; final ComponentName mHotwordDetectionComponentName; final int mUser; final Context mContext; volatile HotwordDetectionServiceIdentity mIdentity; Loading @@ -122,27 +122,30 @@ final class HotwordDetectionConnection { * to record the detectors. */ @GuardedBy("mLock") private final SparseArray<HotwordDetectorSession> mHotwordDetectorSessions = private final SparseArray<DetectorSession> mDetectorSessions = new SparseArray<>(); HotwordDetectionConnection(Object lock, Context context, int voiceInteractionServiceUid, Identity voiceInteractorIdentity, ComponentName serviceName, int userId, Identity voiceInteractorIdentity, ComponentName hotwordDetectionServiceName, int userId, boolean bindInstantServiceAllowed, int detectorType) { mLock = lock; mContext = context; mVoiceInteractionServiceUid = voiceInteractionServiceUid; mVoiceInteractorIdentity = voiceInteractorIdentity; mDetectionComponentName = serviceName; mHotwordDetectionComponentName = hotwordDetectionServiceName; mUser = userId; mDetectorType = detectorType; mReStartPeriodSeconds = DeviceConfig.getInt(DeviceConfig.NAMESPACE_VOICE_INTERACTION, KEY_RESTART_PERIOD_IN_SECONDS, 0); final Intent intent = new Intent(HotwordDetectionService.SERVICE_INTERFACE); intent.setComponent(mDetectionComponentName); final Intent hotwordDetectionServiceIntent = new Intent(HotwordDetectionService.SERVICE_INTERFACE); hotwordDetectionServiceIntent.setComponent(mHotwordDetectionComponentName); initAudioFlingerLocked(); mServiceConnectionFactory = new ServiceConnectionFactory(intent, bindInstantServiceAllowed); mRemoteHotwordDetectionService = mServiceConnectionFactory.createLocked(); mHotwordDetectionServiceConnectionFactory = new ServiceConnectionFactory(hotwordDetectionServiceIntent, bindInstantServiceAllowed); mRemoteHotwordDetectionService = mHotwordDetectionServiceConnectionFactory.createLocked(); mLastRestartInstant = Instant.now(); if (mReStartPeriodSeconds <= 0) { Loading Loading @@ -176,8 +179,8 @@ final class HotwordDetectionConnection { try { mAudioFlinger.linkToDeath(mAudioServerDeathRecipient, /* flags= */ 0); } catch (RemoteException e) { Slog.w(TAG, "Audio server died before we registered a DeathRecipient; retrying init.", e); Slog.w(TAG, "Audio server died before we registered a DeathRecipient; " + "retrying init.", e); initAudioFlingerLocked(); } } Loading @@ -200,10 +203,10 @@ final class HotwordDetectionConnection { void cancelLocked() { Slog.v(TAG, "cancelLocked"); clearDebugHotwordLoggingTimeoutLocked(); runForEachHotwordDetectorSessionLocked((session) -> { runForEachDetectorSessionLocked((session) -> { session.destroyLocked(); }); mHotwordDetectorSessions.clear(); mDetectorSessions.clear(); mDebugHotwordLogging = false; mRemoteHotwordDetectionService.unbind(); LocalServices.getService(PermissionManagerServiceInternal.class) Loading @@ -223,7 +226,7 @@ final class HotwordDetectionConnection { @SuppressWarnings("GuardedBy") void updateStateLocked(PersistableBundle options, SharedMemory sharedMemory, @NonNull IBinder token) { final HotwordDetectorSession session = getDetectorSessionByTokenLocked(token); final DetectorSession session = getDetectorSessionByTokenLocked(token); if (session == null) { Slog.v(TAG, "Not found the detector by token"); return; Loading Loading @@ -259,7 +262,7 @@ final class HotwordDetectionConnection { if (DEBUG) { Slog.d(TAG, "startListeningFromExternalSourceLocked"); } final HotwordDetectorSession session = getDetectorSessionByTokenLocked(token); final DetectorSession session = getDetectorSessionByTokenLocked(token); if (session == null) { Slog.v(TAG, "Not found the detector by token"); return; Loading Loading @@ -321,7 +324,7 @@ final class HotwordDetectionConnection { Slog.v(TAG, "setDebugHotwordLoggingLocked: " + logging); clearDebugHotwordLoggingTimeoutLocked(); mDebugHotwordLogging = logging; runForEachHotwordDetectorSessionLocked((session) -> { runForEachDetectorSessionLocked((session) -> { session.setDebugHotwordLoggingLocked(logging); }); Loading @@ -331,7 +334,7 @@ final class HotwordDetectionConnection { Slog.v(TAG, "Timeout to reset mDebugHotwordLogging to false"); synchronized (mLock) { mDebugHotwordLogging = false; runForEachHotwordDetectorSessionLocked((session) -> { runForEachDetectorSessionLocked((session) -> { session.setDebugHotwordLoggingLocked(false); }); } Loading @@ -350,24 +353,24 @@ final class HotwordDetectionConnection { private void restartProcessLocked() { // TODO(b/244598068): Check HotwordAudioStreamManager first Slog.v(TAG, "Restarting hotword detection process"); ServiceConnection oldConnection = mRemoteHotwordDetectionService; ServiceConnection oldHotwordConnection = mRemoteHotwordDetectionService; HotwordDetectionServiceIdentity previousIdentity = mIdentity; mLastRestartInstant = Instant.now(); // Recreate connection to reset the cache. mRemoteHotwordDetectionService = mServiceConnectionFactory.createLocked(); mRemoteHotwordDetectionService = mHotwordDetectionServiceConnectionFactory.createLocked(); Slog.v(TAG, "Started the new process, dispatching processRestarted to detector"); runForEachHotwordDetectorSessionLocked((session) -> { session.updateRemoteHotwordDetectionServiceLocked(mRemoteHotwordDetectionService); runForEachDetectorSessionLocked((session) -> { session.updateRemoteSandboxedDetectionServiceLocked(mRemoteHotwordDetectionService); session.informRestartProcessLocked(); }); if (DEBUG) { Slog.i(TAG, "processRestarted is dispatched done, unbinding from the old process"); } oldConnection.ignoreConnectionStatusEvents(); oldConnection.unbind(); oldHotwordConnection.ignoreConnectionStatusEvents(); oldHotwordConnection.unbind(); if (previousIdentity != null) { removeServiceUidForAudioPolicy(previousIdentity.getIsolatedUid()); } Loading Loading @@ -437,12 +440,12 @@ final class HotwordDetectionConnection { pw.print(prefix); pw.print("mBound="); pw.println(mRemoteHotwordDetectionService.isBound()); pw.print(prefix); pw.print("mRestartCount="); pw.println(mServiceConnectionFactory.mRestartCount); pw.println(mHotwordDetectionServiceConnectionFactory.mRestartCount); pw.print(prefix); pw.print("mLastRestartInstant="); pw.println(mLastRestartInstant); pw.print(prefix); pw.print("mDetectorType="); pw.println(HotwordDetector.detectorTypeToString(mDetectorType)); pw.print(prefix); pw.println("HotwordDetectorSession(s)"); runForEachHotwordDetectorSessionLocked((session) -> { pw.print(prefix); pw.println("DetectorSession(s)"); runForEachDetectorSessionLocked((session) -> { session.dumpLocked(prefix, pw); }); } Loading Loading @@ -537,9 +540,9 @@ final class HotwordDetectionConnection { } } synchronized (HotwordDetectionConnection.this.mLock) { runForEachHotwordDetectorSessionLocked((session) -> { runForEachDetectorSessionLocked((session) -> { session.reportErrorLocked( HotwordDetectorSession.HOTWORD_DETECTION_SERVICE_DIED); DetectorSession.HOTWORD_DETECTION_SERVICE_DIED); }); } // Can improve to log exit reason if needed Loading Loading @@ -599,12 +602,12 @@ final class HotwordDetectionConnection { int detectorType) { // We only support one Dsp trusted hotword detector and one software hotword detector at // the same time, remove existing one. HotwordDetectorSession removeSession = mHotwordDetectorSessions.get(detectorType); DetectorSession removeSession = mDetectorSessions.get(detectorType); if (removeSession != null) { removeSession.destroyLocked(); mHotwordDetectorSessions.remove(detectorType); mDetectorSessions.remove(detectorType); } final HotwordDetectorSession session; final DetectorSession session; if (detectorType == HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_DSP) { session = new DspTrustedHotwordDetectorSession(mRemoteHotwordDetectionService, mLock, mContext, token, callback, mVoiceInteractionServiceUid, Loading @@ -615,30 +618,30 @@ final class HotwordDetectionConnection { mVoiceInteractionServiceUid, mVoiceInteractorIdentity, mScheduledExecutorService, mDebugHotwordLogging); } mHotwordDetectorSessions.put(detectorType, session); mDetectorSessions.put(detectorType, session); session.initialize(options, sharedMemory); } @SuppressWarnings("GuardedBy") void destroyDetectorLocked(@NonNull IBinder token) { final HotwordDetectorSession session = getDetectorSessionByTokenLocked(token); final DetectorSession session = getDetectorSessionByTokenLocked(token); if (session != null) { session.destroyLocked(); final int index = mHotwordDetectorSessions.indexOfValue(session); if (index < 0 || index > mHotwordDetectorSessions.size() - 1) { final int index = mDetectorSessions.indexOfValue(session); if (index < 0 || index > mDetectorSessions.size() - 1) { return; } mHotwordDetectorSessions.removeAt(index); mDetectorSessions.removeAt(index); } } @SuppressWarnings("GuardedBy") private HotwordDetectorSession getDetectorSessionByTokenLocked(IBinder token) { private DetectorSession getDetectorSessionByTokenLocked(IBinder token) { if (token == null) { return null; } for (int i = 0; i < mHotwordDetectorSessions.size(); i++) { final HotwordDetectorSession session = mHotwordDetectorSessions.valueAt(i); for (int i = 0; i < mDetectorSessions.size(); i++) { final DetectorSession session = mDetectorSessions.valueAt(i); if (!session.isDestroyed() && session.isSameToken(token)) { return session; } Loading @@ -648,7 +651,7 @@ final class HotwordDetectionConnection { @SuppressWarnings("GuardedBy") private DspTrustedHotwordDetectorSession getDspTrustedHotwordDetectorSessionLocked() { final HotwordDetectorSession session = mHotwordDetectorSessions.get( final DetectorSession session = mDetectorSessions.get( HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_DSP); if (session == null || session.isDestroyed()) { Slog.v(TAG, "Not found the Dsp detector"); Loading @@ -659,7 +662,7 @@ final class HotwordDetectionConnection { @SuppressWarnings("GuardedBy") private SoftwareTrustedHotwordDetectorSession getSoftwareTrustedHotwordDetectorSessionLocked() { final HotwordDetectorSession session = mHotwordDetectorSessions.get( final DetectorSession session = mDetectorSessions.get( HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_SOFTWARE); if (session == null || session.isDestroyed()) { Slog.v(TAG, "Not found the software detector"); Loading @@ -669,10 +672,10 @@ final class HotwordDetectionConnection { } @SuppressWarnings("GuardedBy") private void runForEachHotwordDetectorSessionLocked( @NonNull Consumer<HotwordDetectorSession> action) { for (int i = 0; i < mHotwordDetectorSessions.size(); i++) { HotwordDetectorSession session = mHotwordDetectorSessions.valueAt(i); private void runForEachDetectorSessionLocked( @NonNull Consumer<DetectorSession> action) { for (int i = 0; i < mDetectorSessions.size(); i++) { DetectorSession session = mDetectorSessions.valueAt(i); action.accept(session); } } Loading
services/voiceinteraction/java/com/android/server/voiceinteraction/SoftwareTrustedHotwordDetectorSession.java +3 −3 Original line number Diff line number Diff line Loading @@ -55,7 +55,7 @@ import java.util.concurrent.ScheduledExecutorService; * {@link android.service.voice.VoiceInteractionService#createHotwordDetector(PersistableBundle, * SharedMemory, HotwordDetector.Callback)}. */ final class SoftwareTrustedHotwordDetectorSession extends HotwordDetectorSession { final class SoftwareTrustedHotwordDetectorSession extends DetectorSession { private static final String TAG = "SoftwareTrustedHotwordDetectorSession"; private IMicrophoneHotwordDetectionVoiceInteractionCallback mSoftwareCallback; Loading Loading @@ -155,7 +155,7 @@ final class SoftwareTrustedHotwordDetectorSession extends HotwordDetectorSession } }; mRemoteHotwordDetectionService.run( mRemoteDetectionService.run( service -> service.detectFromMicrophoneSource( null, AUDIO_SOURCE_MICROPHONE, Loading @@ -179,7 +179,7 @@ final class SoftwareTrustedHotwordDetectorSession extends HotwordDetectorSession } mPerformingSoftwareHotwordDetection = false; mRemoteHotwordDetectionService.run(ISandboxedDetectionService::stopDetection); mRemoteDetectionService.run(ISandboxedDetectionService::stopDetection); closeExternalAudioStreamLocked("stopping requested"); } Loading