From fc651fe0d2fcd2a29ba5988603318d4ef782d943 Mon Sep 17 00:00:00 2001 From: Ahaan Ugale Date: Mon, 14 Mar 2022 22:51:10 -0700 Subject: [PATCH] Trusted Hotword: Allow disabling periodic restarts. Mitigates quality risk that may arise due to mismanaged state around the restarts (either on the platform or application side). The duration will be flag-controlled in a follow-up cl so it can actually be disabled by flag. Bug: 224618257 Test: manual Change-Id: I3b17b47fab4120b42d75443b213be3c1ef5491aa (cherry picked from commit b8cd0a4286811bb72a96fc98e95a1f7e7edcdf24) Merged-in: I3b17b47fab4120b42d75443b213be3c1ef5491aa --- .../HotwordDetectionConnection.java | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java index d7a5f0a52ddf5..f08f8491264a0 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java @@ -115,6 +115,11 @@ final class HotwordDetectionConnection { private static final Duration MAX_UPDATE_TIMEOUT_DURATION = Duration.ofMillis(MAX_UPDATE_TIMEOUT_MILLIS); private static final long RESET_DEBUG_HOTWORD_LOGGING_TIMEOUT_MILLIS = 60 * 60 * 1000; // 1 hour + /** + * Time after which each HotwordDetectionService process is stopped and replaced by a new one. + * 0 indicates no restarts. + */ + private static final int RESTART_PERIOD_SECONDS = 3600; // 60 minutes private static final int MAX_ISOLATED_PROCESS_NUMBER = 10; // Hotword metrics @@ -133,6 +138,7 @@ final class HotwordDetectionConnection { // TODO: This may need to be a Handler(looper) private final ScheduledExecutorService mScheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); + @Nullable private final ScheduledFuture mCancellationTaskFuture; private final AtomicBoolean mUpdateStateAfterStartFinished = new AtomicBoolean(false); private final IBinder.DeathRecipient mAudioServerDeathRecipient = this::audioServerDied; private final @NonNull ServiceConnectionFactory mServiceConnectionFactory; @@ -148,7 +154,6 @@ final class HotwordDetectionConnection { private IMicrophoneHotwordDetectionVoiceInteractionCallback mSoftwareCallback; private Instant mLastRestartInstant; - private ScheduledFuture mCancellationTaskFuture; private ScheduledFuture mCancellationKeyPhraseDetectionFuture; private ScheduledFuture mDebugHotwordLoggingTimeoutFuture = null; @@ -194,16 +199,20 @@ final class HotwordDetectionConnection { mLastRestartInstant = Instant.now(); updateStateAfterProcessStart(options, sharedMemory); - // TODO(volnov): we need to be smarter here, e.g. schedule it a bit more often, but wait - // until the current session is closed. - mCancellationTaskFuture = mScheduledExecutorService.scheduleAtFixedRate(() -> { - Slog.v(TAG, "Time to restart the process, TTL has passed"); - synchronized (mLock) { - restartProcessLocked(); - HotwordMetricsLogger.writeServiceRestartEvent(mDetectorType, - HOTWORD_DETECTION_SERVICE_RESTARTED__REASON__SCHEDULE); - } - }, 30, 30, TimeUnit.MINUTES); + if (RESTART_PERIOD_SECONDS <= 0) { + mCancellationTaskFuture = null; + } else { + // TODO(volnov): we need to be smarter here, e.g. schedule it a bit more often, but wait + // until the current session is closed. + mCancellationTaskFuture = mScheduledExecutorService.scheduleAtFixedRate(() -> { + Slog.v(TAG, "Time to restart the process, TTL has passed"); + synchronized (mLock) { + restartProcessLocked(); + HotwordMetricsLogger.writeServiceRestartEvent(mDetectorType, + HOTWORD_DETECTION_SERVICE_RESTARTED__REASON__SCHEDULE); + } + }, RESTART_PERIOD_SECONDS, RESTART_PERIOD_SECONDS, TimeUnit.SECONDS); + } } private void initAudioFlingerLocked() { @@ -341,7 +350,9 @@ final class HotwordDetectionConnection { .setHotwordDetectionServiceProvider(null); mIdentity = null; updateServiceUidForAudioPolicy(Process.INVALID_UID); - mCancellationTaskFuture.cancel(/* may interrupt */ true); + if (mCancellationTaskFuture != null) { + mCancellationTaskFuture.cancel(/* may interrupt */ true); + } if (mAudioFlinger != null) { mAudioFlinger.unlinkToDeath(mAudioServerDeathRecipient, /* flags= */ 0); } @@ -759,6 +770,7 @@ final class HotwordDetectionConnection { } public void dump(String prefix, PrintWriter pw) { + pw.print(prefix); pw.print("RESTART_PERIOD_SECONDS="); pw.println(RESTART_PERIOD_SECONDS); pw.print(prefix); pw.print("mBound=" + mRemoteHotwordDetectionService.isBound()); pw.print(", mValidatingDspTrigger=" + mValidatingDspTrigger);