From c9eee6c718bcd9c6b24e3035838665283da555c9 Mon Sep 17 00:00:00 2001 From: Ivan Chiang Date: Fri, 9 Dec 2022 06:24:29 +0000 Subject: Hotword: Use new Audio Egress metrics instead of older one Bug: 261793715 Test: stasd_drive Change-Id: I3baf29a547ee69bee7cae4ca7432c489b0bcb700 --- .../voiceinteraction/HotwordAudioStreamCopier.java | 69 +++++++++++++--------- .../voiceinteraction/HotwordMetricsLogger.java | 30 ++++++++++ 2 files changed, 70 insertions(+), 29 deletions(-) diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java index 81cd1945589e..f896dc1af0b6 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java @@ -19,13 +19,13 @@ package com.android.server.voiceinteraction; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.service.voice.HotwordAudioStream.KEY_AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES; -import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_CLOSE_ERROR_FROM_SYSTEM; -import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_EMPTY_AUDIO_STREAM_LIST; -import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_END; -import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_ILLEGAL_COPY_BUFFER_SIZE; -import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_INTERRUPTED_EXCEPTION; -import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_NO_PERMISSION; -import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_START; +import static com.android.internal.util.FrameworkStatsLog.HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__CLOSE_ERROR_FROM_SYSTEM; +import static com.android.internal.util.FrameworkStatsLog.HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__EMPTY_AUDIO_STREAM_LIST; +import static com.android.internal.util.FrameworkStatsLog.HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__ENDED; +import static com.android.internal.util.FrameworkStatsLog.HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__ILLEGAL_COPY_BUFFER_SIZE; +import static com.android.internal.util.FrameworkStatsLog.HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__INTERRUPTED_EXCEPTION; +import static com.android.internal.util.FrameworkStatsLog.HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__NO_PERMISSION; +import static com.android.internal.util.FrameworkStatsLog.HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__STARTED; import static com.android.server.voiceinteraction.HotwordDetectionConnection.DEBUG; import android.annotation.NonNull; @@ -98,12 +98,14 @@ final class HotwordAudioStreamCopier { throws IOException { List audioStreams = result.getAudioStreams(); if (audioStreams.isEmpty()) { - HotwordMetricsLogger.writeDetectorEvent(mDetectorType, - HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_EMPTY_AUDIO_STREAM_LIST, - mVoiceInteractorUid); + HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType, + HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__EMPTY_AUDIO_STREAM_LIST, + mVoiceInteractorUid, /* streamSizeBytes= */ 0, /* bundleSizeBytes= */ 0, + /* streamCount= */ 0); return result; } + final int audioStreamCount = audioStreams.size(); List newAudioStreams = new ArrayList<>(audioStreams.size()); List copyTaskInfos = new ArrayList<>(audioStreams.size()); for (HotwordAudioStream audioStream : audioStreams) { @@ -120,9 +122,10 @@ final class HotwordAudioStreamCopier { if (metadata.containsKey(KEY_AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES)) { copyBufferLength = metadata.getInt(KEY_AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES, -1); if (copyBufferLength < 1 || copyBufferLength > MAX_COPY_BUFFER_LENGTH_BYTES) { - HotwordMetricsLogger.writeDetectorEvent(mDetectorType, - HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_ILLEGAL_COPY_BUFFER_SIZE, - mVoiceInteractorUid); + HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType, + HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__ILLEGAL_COPY_BUFFER_SIZE, + mVoiceInteractorUid, /* streamSizeBytes= */ 0, /* bundleSizeBytes= */ 0, + audioStreamCount); Slog.w(TAG, "Attempted to set an invalid copy buffer length (" + copyBufferLength + ") for: " + audioStream); copyBufferLength = DEFAULT_COPY_BUFFER_LENGTH_BYTES; @@ -183,17 +186,21 @@ final class HotwordAudioStreamCopier { mVoiceInteractorUid, mVoiceInteractorPackageName, mVoiceInteractorAttributionTag, OP_MESSAGE) == MODE_ALLOWED) { try { - HotwordMetricsLogger.writeDetectorEvent(mDetectorType, - HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_START, - mVoiceInteractorUid); + HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType, + HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__STARTED, + mVoiceInteractorUid, /* streamSizeBytes= */ 0, /* bundleSizeBytes= */ 0, + size); // TODO(b/244599891): Set timeout, close after inactivity mExecutorService.invokeAll(tasks); - HotwordMetricsLogger.writeDetectorEvent(mDetectorType, - HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_END, mVoiceInteractorUid); + HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType, + HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__ENDED, + mVoiceInteractorUid, /* streamSizeBytes= */ 0, /* bundleSizeBytes= */ 0, + size); } catch (InterruptedException e) { - HotwordMetricsLogger.writeDetectorEvent(mDetectorType, - HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_INTERRUPTED_EXCEPTION, - mVoiceInteractorUid); + HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType, + HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__INTERRUPTED_EXCEPTION, + mVoiceInteractorUid, /* streamSizeBytes= */ 0, /* bundleSizeBytes= */ 0, + size); Slog.e(TAG, mResultTaskId + ": Task was interrupted", e); bestEffortPropagateError(e.getMessage()); } finally { @@ -202,9 +209,10 @@ final class HotwordAudioStreamCopier { mVoiceInteractorAttributionTag); } } else { - HotwordMetricsLogger.writeDetectorEvent(mDetectorType, - HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_NO_PERMISSION, - mVoiceInteractorUid); + HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType, + HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__NO_PERMISSION, + mVoiceInteractorUid, /* streamSizeBytes= */ 0, /* bundleSizeBytes= */ 0, + size); bestEffortPropagateError( "Failed to obtain RECORD_AUDIO_HOTWORD permission for voice interactor with" + " uid=" + mVoiceInteractorUid @@ -219,9 +227,10 @@ final class HotwordAudioStreamCopier { copyTaskInfo.mSource.closeWithError(errorMessage); copyTaskInfo.mSink.closeWithError(errorMessage); } - HotwordMetricsLogger.writeDetectorEvent(mDetectorType, - HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_CLOSE_ERROR_FROM_SYSTEM, - mVoiceInteractorUid); + HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType, + HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__CLOSE_ERROR_FROM_SYSTEM, + mVoiceInteractorUid, /* streamSizeBytes= */ 0, /* bundleSizeBytes= */ 0, + mCopyTaskInfos.size()); } catch (IOException e) { Slog.e(TAG, mResultTaskId + ": Failed to propagate error", e); } @@ -288,8 +297,10 @@ final class HotwordAudioStreamCopier { mAudioSource.closeWithError(e.getMessage()); mAudioSink.closeWithError(e.getMessage()); Slog.e(TAG, mStreamTaskId + ": Failed to copy audio stream", e); - HotwordMetricsLogger.writeDetectorEvent(mDetectorType, - HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_CLOSE_ERROR_FROM_SYSTEM, mUid); + HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType, + HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__CLOSE_ERROR_FROM_SYSTEM, + mUid, /* streamSizeBytes= */ 0, /* bundleSizeBytes= */ 0, + /* streamCount= */ 0); } finally { if (fis != null) { fis.close(); diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordMetricsLogger.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordMetricsLogger.java index 61c18be6f133..c35d90f4a495 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordMetricsLogger.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordMetricsLogger.java @@ -16,6 +16,9 @@ package com.android.server.voiceinteraction; +import static com.android.internal.util.FrameworkStatsLog.HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__DETECTOR_TYPE__NORMAL_DETECTOR; +import static com.android.internal.util.FrameworkStatsLog.HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP; +import static com.android.internal.util.FrameworkStatsLog.HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE; import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__DETECTOR_TYPE__NORMAL_DETECTOR; import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP; import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE; @@ -47,6 +50,12 @@ public final class HotwordMetricsLogger { HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP; private static final int METRICS_INIT_NORMAL_DETECTOR = HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__DETECTOR_TYPE__NORMAL_DETECTOR; + private static final int AUDIO_EGRESS_DSP_DETECTOR = + HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP; + private static final int AUDIO_EGRESS_SOFTWARE_DETECTOR = + HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE; + private static final int AUDIO_EGRESS_NORMAL_DETECTOR = + HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__DETECTOR_TYPE__NORMAL_DETECTOR; private HotwordMetricsLogger() { // Class only contains static utility functions, and should not be instantiated @@ -97,6 +106,16 @@ public final class HotwordMetricsLogger { metricsDetectorType, event, uid); } + /** + * Logs information related to hotword audio egress events. + */ + public static void writeAudioEgressEvent(int detectorType, int event, int uid, + int streamSizeBytes, int bundleSizeBytes, int streamCount) { + int metricsDetectorType = getAudioEgressDetectorType(detectorType); + FrameworkStatsLog.write(FrameworkStatsLog.HOTWORD_AUDIO_EGRESS_EVENT_REPORTED, + metricsDetectorType, event, uid, streamSizeBytes, bundleSizeBytes, streamCount); + } + private static int getCreateMetricsDetectorType(int detectorType) { switch (detectorType) { case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_SOFTWARE: @@ -151,4 +170,15 @@ public final class HotwordMetricsLogger { return HOTWORD_DETECTOR_EVENTS__DETECTOR_TYPE__NORMAL_DETECTOR; } } + + private static int getAudioEgressDetectorType(int detectorType) { + switch (detectorType) { + case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_SOFTWARE: + return AUDIO_EGRESS_SOFTWARE_DETECTOR; + case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_DSP: + return AUDIO_EGRESS_DSP_DETECTOR; + default: + return AUDIO_EGRESS_NORMAL_DETECTOR; + } + } } -- cgit v1.2.3-59-g8ed1b From 0059e51a1bcf19b7fa254d1c370151bc200e9766 Mon Sep 17 00:00:00 2001 From: Mark Punzalan Date: Thu, 15 Dec 2022 09:32:47 +0000 Subject: Populate data sizes in audio egress metrics The stream and metadata sizes are summed across all HotwordAudioStreams in the HotwordDetectedResult. Also logged the same byte sizes. Bug: 261793715 Bug: 244599440 Test: `statsd_testdrive 578` with sample app. The sizes in the metrics are the same as the ones logged, and the values are in line with what the sample app is sending in the HotwordDetectedResult. Change-Id: I48279bba854e3e6badc530fa485bb46c2097ce44 --- .../voiceinteraction/HotwordAudioStreamCopier.java | 38 ++++++++++++++++++---- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java index f896dc1af0b6..a15417a1d588 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java @@ -108,6 +108,7 @@ final class HotwordAudioStreamCopier { final int audioStreamCount = audioStreams.size(); List newAudioStreams = new ArrayList<>(audioStreams.size()); List copyTaskInfos = new ArrayList<>(audioStreams.size()); + int totalMetadataBundleSizeBytes = 0; for (HotwordAudioStream audioStream : audioStreams) { ParcelFileDescriptor[] clientPipe = ParcelFileDescriptor.createReliablePipe(); ParcelFileDescriptor clientAudioSource = clientPipe[0]; @@ -119,6 +120,7 @@ final class HotwordAudioStreamCopier { int copyBufferLength = DEFAULT_COPY_BUFFER_LENGTH_BYTES; PersistableBundle metadata = audioStream.getMetadata(); + totalMetadataBundleSizeBytes += HotwordDetectedResult.getParcelableSize(metadata); if (metadata.containsKey(KEY_AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES)) { copyBufferLength = metadata.getInt(KEY_AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES, -1); if (copyBufferLength < 1 || copyBufferLength > MAX_COPY_BUFFER_LENGTH_BYTES) { @@ -142,7 +144,9 @@ final class HotwordAudioStreamCopier { } String resultTaskId = TASK_ID_PREFIX + System.identityHashCode(result); - mExecutorService.execute(new HotwordDetectedResultCopyTask(resultTaskId, copyTaskInfos)); + mExecutorService.execute( + new HotwordDetectedResultCopyTask(resultTaskId, copyTaskInfos, + totalMetadataBundleSizeBytes)); return result.buildUpon().setAudioStreams(newAudioStreams).build(); } @@ -162,11 +166,14 @@ final class HotwordAudioStreamCopier { private class HotwordDetectedResultCopyTask implements Runnable { private final String mResultTaskId; private final List mCopyTaskInfos; + private final int mTotalMetadataSizeBytes; private final ExecutorService mExecutorService = Executors.newCachedThreadPool(); - HotwordDetectedResultCopyTask(String resultTaskId, List copyTaskInfos) { + HotwordDetectedResultCopyTask(String resultTaskId, List copyTaskInfos, + int totalMetadataSizeBytes) { mResultTaskId = resultTaskId; mCopyTaskInfos = copyTaskInfos; + mTotalMetadataSizeBytes = totalMetadataSizeBytes; } @Override @@ -188,20 +195,36 @@ final class HotwordAudioStreamCopier { try { HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType, HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__STARTED, - mVoiceInteractorUid, /* streamSizeBytes= */ 0, /* bundleSizeBytes= */ 0, + mVoiceInteractorUid, /* streamSizeBytes= */ 0, mTotalMetadataSizeBytes, size); // TODO(b/244599891): Set timeout, close after inactivity mExecutorService.invokeAll(tasks); + + int totalStreamSizeBytes = 0; + for (SingleAudioStreamCopyTask task : tasks) { + totalStreamSizeBytes += task.mTotalCopiedBytes; + } + + Slog.i(TAG, mResultTaskId + ": Task was completed. Total bytes streamed: " + + totalStreamSizeBytes + ", total metadata bundle size bytes: " + + mTotalMetadataSizeBytes); HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType, HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__ENDED, - mVoiceInteractorUid, /* streamSizeBytes= */ 0, /* bundleSizeBytes= */ 0, + mVoiceInteractorUid, totalStreamSizeBytes, mTotalMetadataSizeBytes, size); } catch (InterruptedException e) { + int totalStreamSizeBytes = 0; + for (SingleAudioStreamCopyTask task : tasks) { + totalStreamSizeBytes += task.mTotalCopiedBytes; + } + HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType, HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__INTERRUPTED_EXCEPTION, - mVoiceInteractorUid, /* streamSizeBytes= */ 0, /* bundleSizeBytes= */ 0, + mVoiceInteractorUid, totalStreamSizeBytes, mTotalMetadataSizeBytes, size); - Slog.e(TAG, mResultTaskId + ": Task was interrupted", e); + Slog.e(TAG, mResultTaskId + ": Task was interrupted. Total bytes streamed: " + + totalStreamSizeBytes + ", total metadata bundle size bytes: " + + mTotalMetadataSizeBytes); bestEffortPropagateError(e.getMessage()); } finally { mAppOpsManager.finishOp(AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD, @@ -246,6 +269,8 @@ final class HotwordAudioStreamCopier { private final int mDetectorType; private final int mUid; + private volatile int mTotalCopiedBytes = 0; + SingleAudioStreamCopyTask(String streamTaskId, ParcelFileDescriptor audioSource, ParcelFileDescriptor audioSink, int copyBufferLength, int detectorType, int uid) { mStreamTaskId = streamTaskId; @@ -290,6 +315,7 @@ final class HotwordAudioStreamCopier { Arrays.copyOfRange(buffer, 0, 20))); } fos.write(buffer, 0, bytesRead); + mTotalCopiedBytes += bytesRead; } // TODO(b/244599891): Close PFDs after inactivity } -- cgit v1.2.3-59-g8ed1b