diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java index 655bfe2a1a464..965f126000fd8 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java @@ -94,6 +94,7 @@ final class HotwordDetectionConnection { private static final long MAX_UPDATE_TIMEOUT_MILLIS = 6000; 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 private final Executor mAudioCopyExecutor = Executors.newCachedThreadPool(); // TODO: This may need to be a Handler(looper) @@ -114,6 +115,7 @@ final class HotwordDetectionConnection { private Instant mLastRestartInstant; private ScheduledFuture mCancellationTaskFuture; + private ScheduledFuture mDebugHotwordLoggingTimeoutFuture = null; /** Identity used for attributing app ops when delivering data to the Interactor. */ @GuardedBy("mLock") @@ -127,6 +129,7 @@ final class HotwordDetectionConnection { private boolean mPerformingSoftwareHotwordDetection; private @NonNull ServiceConnection mRemoteHotwordDetectionService; private IBinder mAudioFlinger; + private boolean mDebugHotwordLogging = false; HotwordDetectionConnection(Object lock, Context context, int voiceInteractionServiceUid, Identity voiceInteractorIdentity, ComponentName serviceName, int userId, @@ -265,6 +268,8 @@ final class HotwordDetectionConnection { void cancelLocked() { Slog.v(TAG, "cancelLocked"); + clearDebugHotwordLoggingTimeoutLocked(); + mDebugHotwordLogging = false; if (mRemoteHotwordDetectionService.isBound()) { mRemoteHotwordDetectionService.unbind(); LocalServices.getService(PermissionManagerServiceInternal.class) @@ -325,6 +330,9 @@ final class HotwordDetectionConnection { if (result != null) { Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(result) + " bits from hotword trusted process"); + if (mDebugHotwordLogging) { + Slog.i(TAG, "Egressed detected result: " + result); + } } } else { Slog.i(TAG, "Hotword detection has already completed"); @@ -415,6 +423,9 @@ final class HotwordDetectionConnection { if (result != null) { Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(result) + " bits from hotword trusted process"); + if (mDebugHotwordLogging) { + Slog.i(TAG, "Egressed detected result: " + result); + } } } else { Slog.i(TAG, "Ignored hotword detected since trigger has been handled"); @@ -429,6 +440,9 @@ final class HotwordDetectionConnection { if (mValidatingDspTrigger) { mValidatingDspTrigger = false; externalCallback.onRejected(result); + if (mDebugHotwordLogging && result != null) { + Slog.i(TAG, "Egressed rejected result: " + result); + } } else { Slog.i(TAG, "Ignored hotword rejected since trigger has been handled"); } @@ -471,6 +485,9 @@ final class HotwordDetectionConnection { if (result != null) { Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(result) + " bits from hotword trusted process"); + if (mDebugHotwordLogging) { + Slog.i(TAG, "Egressed detected result: " + result); + } } } } @@ -487,6 +504,9 @@ final class HotwordDetectionConnection { } mValidatingDspTrigger = false; externalCallback.onRejected(result); + if (mDebugHotwordLogging && result != null) { + Slog.i(TAG, "Egressed rejected result: " + result); + } } } }; @@ -509,6 +529,29 @@ final class HotwordDetectionConnection { } } + void setDebugHotwordLoggingLocked(boolean logging) { + Slog.v(TAG, "setDebugHotwordLoggingLocked: " + logging); + clearDebugHotwordLoggingTimeoutLocked(); + mDebugHotwordLogging = logging; + + if (logging) { + // Reset mDebugHotwordLogging to false after one hour + mDebugHotwordLoggingTimeoutFuture = mScheduledExecutorService.schedule(() -> { + Slog.v(TAG, "Timeout to reset mDebugHotwordLogging to false"); + synchronized (mLock) { + mDebugHotwordLogging = false; + } + }, RESET_DEBUG_HOTWORD_LOGGING_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); + } + } + + private void clearDebugHotwordLoggingTimeoutLocked() { + if (mDebugHotwordLoggingTimeoutFuture != null) { + mDebugHotwordLoggingTimeoutFuture.cancel(/* mayInterruptIfRunning= */true); + mDebugHotwordLoggingTimeoutFuture = null; + } + } + private void restartProcessLocked() { Slog.v(TAG, "Restarting hotword detection process"); ServiceConnection oldConnection = mRemoteHotwordDetectionService; @@ -682,6 +725,9 @@ final class HotwordDetectionConnection { bestEffortClose(serviceAudioSource); bestEffortClose(audioSource); + if (mDebugHotwordLogging && result != null) { + Slog.i(TAG, "Egressed rejected result: " + result); + } // TODO: Propagate the HotwordRejectedResult. } @@ -696,6 +742,9 @@ final class HotwordDetectionConnection { if (triggerResult != null) { Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize( triggerResult) + " bits from hotword trusted process"); + if (mDebugHotwordLogging) { + Slog.i(TAG, "Egressed detected result: " + triggerResult); + } } // TODO: Add a delay before closing. bestEffortClose(audioSource); diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index ccf4267a0fbce..71541ad729d53 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -832,6 +832,17 @@ public class VoiceInteractionManagerService extends SystemService { mImpl.forceRestartHotwordDetector(); } + // Called by Shell command + void setDebugHotwordLogging(boolean logging) { + synchronized (this) { + if (mImpl == null) { + Slog.w(TAG, "setTemporaryLogging without running voice interaction service"); + return; + } + mImpl.setDebugHotwordLoggingLocked(logging); + } + } + @Override public void showSession(Bundle args, int flags) { synchronized (this) { diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java index 92fe33a3b8703..558a9ac9298ea 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java @@ -581,6 +581,14 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mHotwordDetectionConnection.forceRestart(); } + void setDebugHotwordLoggingLocked(boolean logging) { + if (mHotwordDetectionConnection == null) { + Slog.w(TAG, "Failed to set temporary debug logging: no hotword detection active"); + return; + } + mHotwordDetectionConnection.setDebugHotwordLoggingLocked(logging); + } + void resetHotwordDetectionConnectionLocked() { if (DEBUG) { Slog.d(TAG, "resetHotwordDetectionConnectionLocked"); diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java index cdd8f7b91d9d8..9bdf4e418a527 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java @@ -56,6 +56,8 @@ final class VoiceInteractionManagerServiceShellCommand extends ShellCommand { return requestDisable(pw); case "restart-detection": return requestRestartDetection(pw); + case "set-debug-hotword-logging": + return setDebugHotwordLogging(pw); default: return handleDefaultCommands(cmd); } @@ -76,9 +78,14 @@ final class VoiceInteractionManagerServiceShellCommand extends ShellCommand { pw.println(""); pw.println(" disable [true|false]"); pw.println(" Temporarily disable (when true) service"); + pw.println(""); pw.println(" restart-detection"); pw.println(" Force a restart of a hotword detection service"); pw.println(""); + pw.println(" set-debug-hotword-logging [true|false]"); + pw.println(" Temporarily enable or disable debug logging for hotword result."); + pw.println(" The debug logging will be reset after one hour from last enable."); + pw.println(""); } } @@ -157,6 +164,17 @@ final class VoiceInteractionManagerServiceShellCommand extends ShellCommand { return 0; } + private int setDebugHotwordLogging(PrintWriter pw) { + boolean logging = Boolean.parseBoolean(getNextArgRequired()); + Slog.i(TAG, "setDebugHotwordLogging(): " + logging); + try { + mService.setDebugHotwordLogging(logging); + } catch (Exception e) { + return handleError(pw, "setDebugHotwordLogging()", e); + } + return 0; + } + private static int handleError(PrintWriter pw, String message, Exception e) { Slog.e(TAG, "error calling " + message, e); pw.printf("Error calling %s: %s\n", message, e);