Loading services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java +69 −32 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -98,14 +98,17 @@ final class HotwordAudioStreamCopier { throws IOException { List<HotwordAudioStream> 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<HotwordAudioStream> newAudioStreams = new ArrayList<>(audioStreams.size()); List<CopyTaskInfo> copyTaskInfos = new ArrayList<>(audioStreams.size()); int totalMetadataBundleSizeBytes = 0; for (HotwordAudioStream audioStream : audioStreams) { ParcelFileDescriptor[] clientPipe = ParcelFileDescriptor.createReliablePipe(); ParcelFileDescriptor clientAudioSource = clientPipe[0]; Loading @@ -117,12 +120,14 @@ 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) { 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; Loading @@ -139,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(); } Loading @@ -159,11 +166,14 @@ final class HotwordAudioStreamCopier { private class HotwordDetectedResultCopyTask implements Runnable { private final String mResultTaskId; private final List<CopyTaskInfo> mCopyTaskInfos; private final int mTotalMetadataSizeBytes; private final ExecutorService mExecutorService = Executors.newCachedThreadPool(); HotwordDetectedResultCopyTask(String resultTaskId, List<CopyTaskInfo> copyTaskInfos) { HotwordDetectedResultCopyTask(String resultTaskId, List<CopyTaskInfo> copyTaskInfos, int totalMetadataSizeBytes) { mResultTaskId = resultTaskId; mCopyTaskInfos = copyTaskInfos; mTotalMetadataSizeBytes = totalMetadataSizeBytes; } @Override Loading @@ -183,18 +193,38 @@ 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, mTotalMetadataSizeBytes, size); // TODO(b/244599891): Set timeout, close after inactivity mExecutorService.invokeAll(tasks); HotwordMetricsLogger.writeDetectorEvent(mDetectorType, HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_END, mVoiceInteractorUid); 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, totalStreamSizeBytes, mTotalMetadataSizeBytes, size); } catch (InterruptedException e) { HotwordMetricsLogger.writeDetectorEvent(mDetectorType, HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_INTERRUPTED_EXCEPTION, mVoiceInteractorUid); Slog.e(TAG, mResultTaskId + ": Task was interrupted", e); int totalStreamSizeBytes = 0; for (SingleAudioStreamCopyTask task : tasks) { totalStreamSizeBytes += task.mTotalCopiedBytes; } HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType, HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__INTERRUPTED_EXCEPTION, mVoiceInteractorUid, totalStreamSizeBytes, mTotalMetadataSizeBytes, size); 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, Loading @@ -202,9 +232,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 Loading @@ -219,9 +250,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); } Loading @@ -237,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; Loading Loading @@ -281,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 } Loading @@ -288,8 +323,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(); Loading services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordMetricsLogger.java +30 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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: Loading Loading @@ -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; } } } Loading
services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java +69 −32 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -98,14 +98,17 @@ final class HotwordAudioStreamCopier { throws IOException { List<HotwordAudioStream> 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<HotwordAudioStream> newAudioStreams = new ArrayList<>(audioStreams.size()); List<CopyTaskInfo> copyTaskInfos = new ArrayList<>(audioStreams.size()); int totalMetadataBundleSizeBytes = 0; for (HotwordAudioStream audioStream : audioStreams) { ParcelFileDescriptor[] clientPipe = ParcelFileDescriptor.createReliablePipe(); ParcelFileDescriptor clientAudioSource = clientPipe[0]; Loading @@ -117,12 +120,14 @@ 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) { 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; Loading @@ -139,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(); } Loading @@ -159,11 +166,14 @@ final class HotwordAudioStreamCopier { private class HotwordDetectedResultCopyTask implements Runnable { private final String mResultTaskId; private final List<CopyTaskInfo> mCopyTaskInfos; private final int mTotalMetadataSizeBytes; private final ExecutorService mExecutorService = Executors.newCachedThreadPool(); HotwordDetectedResultCopyTask(String resultTaskId, List<CopyTaskInfo> copyTaskInfos) { HotwordDetectedResultCopyTask(String resultTaskId, List<CopyTaskInfo> copyTaskInfos, int totalMetadataSizeBytes) { mResultTaskId = resultTaskId; mCopyTaskInfos = copyTaskInfos; mTotalMetadataSizeBytes = totalMetadataSizeBytes; } @Override Loading @@ -183,18 +193,38 @@ 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, mTotalMetadataSizeBytes, size); // TODO(b/244599891): Set timeout, close after inactivity mExecutorService.invokeAll(tasks); HotwordMetricsLogger.writeDetectorEvent(mDetectorType, HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_END, mVoiceInteractorUid); 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, totalStreamSizeBytes, mTotalMetadataSizeBytes, size); } catch (InterruptedException e) { HotwordMetricsLogger.writeDetectorEvent(mDetectorType, HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_INTERRUPTED_EXCEPTION, mVoiceInteractorUid); Slog.e(TAG, mResultTaskId + ": Task was interrupted", e); int totalStreamSizeBytes = 0; for (SingleAudioStreamCopyTask task : tasks) { totalStreamSizeBytes += task.mTotalCopiedBytes; } HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType, HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__INTERRUPTED_EXCEPTION, mVoiceInteractorUid, totalStreamSizeBytes, mTotalMetadataSizeBytes, size); 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, Loading @@ -202,9 +232,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 Loading @@ -219,9 +250,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); } Loading @@ -237,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; Loading Loading @@ -281,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 } Loading @@ -288,8 +323,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(); Loading
services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordMetricsLogger.java +30 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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: Loading Loading @@ -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; } } }