Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4e55aa9c authored by Mark Punzalan's avatar Mark Punzalan Committed by Android (Google) Code Review
Browse files

Merge "Enforce DSP detection timeout."

parents bf93bb75 1564a67a
Loading
Loading
Loading
Loading
+32 −78
Original line number Original line Diff line number Diff line
@@ -136,6 +136,7 @@ final class HotwordDetectionConnection {
    // The error codes are used for onError callback
    // The error codes are used for onError callback
    private static final int HOTWORD_DETECTION_SERVICE_DIED = -1;
    private static final int HOTWORD_DETECTION_SERVICE_DIED = -1;
    private static final int CALLBACK_ONDETECTED_GOT_SECURITY_EXCEPTION = -2;
    private static final int CALLBACK_ONDETECTED_GOT_SECURITY_EXCEPTION = -2;
    private static final int CALLBACK_DETECT_TIMEOUT = -3;


    // Hotword metrics
    // Hotword metrics
    private static final int METRICS_INIT_UNKNOWN_TIMEOUT =
    private static final int METRICS_INIT_UNKNOWN_TIMEOUT =
@@ -545,66 +546,7 @@ final class HotwordDetectionConnection {
        if (DEBUG) {
        if (DEBUG) {
            Slog.d(TAG, "triggerHardwareRecognitionEventForTestLocked");
            Slog.d(TAG, "triggerHardwareRecognitionEventForTestLocked");
        }
        }
        detectFromDspSourceForTest(event, callback);
        detectFromDspSource(event, callback);
    }

    private void detectFromDspSourceForTest(SoundTrigger.KeyphraseRecognitionEvent recognitionEvent,
            IHotwordRecognitionStatusCallback externalCallback) {
        Slog.v(TAG, "detectFromDspSourceForTest");
        IDspHotwordDetectionCallback internalCallback = new IDspHotwordDetectionCallback.Stub() {
            @Override
            public void onDetected(HotwordDetectedResult result) throws RemoteException {
                Slog.v(TAG, "onDetected");
                synchronized (mLock) {
                    if (!mValidatingDspTrigger) {
                        Slog.i(TAG, "Ignored hotword detected since trigger has been handled");
                        return;
                    }
                    mValidatingDspTrigger = false;
                    try {
                        enforcePermissionsForDataDelivery();
                        enforceExtraKeyphraseIdNotLeaked(result, recognitionEvent);
                    } catch (SecurityException e) {
                        externalCallback.onError(CALLBACK_ONDETECTED_GOT_SECURITY_EXCEPTION);
                        return;
                    }
                    externalCallback.onKeyphraseDetected(recognitionEvent, result);
                    if (result != null) {
                        Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(result)
                                + " bits from hotword trusted process");
                        if (mDebugHotwordLogging) {
                            Slog.i(TAG, "Egressed detected result: " + result);
                        }
                    }
                }
            }

            @Override
            public void onRejected(HotwordRejectedResult result) throws RemoteException {
                Slog.v(TAG, "onRejected");
                synchronized (mLock) {
                    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");
                    }
                }
            }
        };

        synchronized (mLock) {
            mValidatingDspTrigger = true;
            mRemoteHotwordDetectionService.run(
                    service -> service.detectFromDspSource(
                            recognitionEvent,
                            recognitionEvent.getCaptureFormat(),
                            VALIDATION_TIMEOUT_MILLIS,
                            internalCallback));
        }
    }
    }


    private void detectFromDspSource(SoundTrigger.KeyphraseRecognitionEvent recognitionEvent,
    private void detectFromDspSource(SoundTrigger.KeyphraseRecognitionEvent recognitionEvent,
@@ -613,6 +555,7 @@ final class HotwordDetectionConnection {
            Slog.d(TAG, "detectFromDspSource");
            Slog.d(TAG, "detectFromDspSource");
        }
        }


        AtomicBoolean timeoutDetected = new AtomicBoolean(false);
        // TODO: consider making this a non-anonymous class.
        // TODO: consider making this a non-anonymous class.
        IDspHotwordDetectionCallback internalCallback = new IDspHotwordDetectionCallback.Stub() {
        IDspHotwordDetectionCallback internalCallback = new IDspHotwordDetectionCallback.Stub() {
            @Override
            @Override
@@ -621,12 +564,12 @@ final class HotwordDetectionConnection {
                    Slog.d(TAG, "onDetected");
                    Slog.d(TAG, "onDetected");
                }
                }
                synchronized (mLock) {
                synchronized (mLock) {
                    // TODO: If the dsp trigger comes in after the timeout, we will log both events.
                    // Because we don't enforce the timeout yet. We should add some synchronizations
                    // within the runnable to prevent the race condition to log both events.
                    if (mCancellationKeyPhraseDetectionFuture != null) {
                    if (mCancellationKeyPhraseDetectionFuture != null) {
                        mCancellationKeyPhraseDetectionFuture.cancel(true);
                        mCancellationKeyPhraseDetectionFuture.cancel(true);
                    }
                    }
                    if (timeoutDetected.get()) {
                        return;
                    }
                    HotwordMetricsLogger.writeKeyphraseTriggerEvent(
                    HotwordMetricsLogger.writeKeyphraseTriggerEvent(
                            mDetectorType,
                            mDetectorType,
                            HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECTED);
                            HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECTED);
@@ -668,6 +611,9 @@ final class HotwordDetectionConnection {
                    if (mCancellationKeyPhraseDetectionFuture != null) {
                    if (mCancellationKeyPhraseDetectionFuture != null) {
                        mCancellationKeyPhraseDetectionFuture.cancel(true);
                        mCancellationKeyPhraseDetectionFuture.cancel(true);
                    }
                    }
                    if (timeoutDetected.get()) {
                        return;
                    }
                    HotwordMetricsLogger.writeKeyphraseTriggerEvent(
                    HotwordMetricsLogger.writeKeyphraseTriggerEvent(
                            mDetectorType,
                            mDetectorType,
                            HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__REJECTED);
                            HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__REJECTED);
@@ -689,13 +635,21 @@ final class HotwordDetectionConnection {


        synchronized (mLock) {
        synchronized (mLock) {
            mValidatingDspTrigger = true;
            mValidatingDspTrigger = true;
            mRemoteHotwordDetectionService.run(
            mRemoteHotwordDetectionService.run(service -> {
                    service -> {
                        // TODO: avoid allocate every time
                mCancellationKeyPhraseDetectionFuture = mScheduledExecutorService.schedule(
                mCancellationKeyPhraseDetectionFuture = mScheduledExecutorService.schedule(
                                () -> HotwordMetricsLogger
                        () -> {
                                        .writeKeyphraseTriggerEvent(mDetectorType,
                            // TODO: avoid allocate every time
                                        HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_TIMEOUT),
                            timeoutDetected.set(true);
                            Slog.w(TAG, "Timed out on #detectFromDspSource");
                            HotwordMetricsLogger.writeKeyphraseTriggerEvent(
                                    mDetectorType,
                                    HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_TIMEOUT);
                            try {
                                externalCallback.onError(CALLBACK_DETECT_TIMEOUT);
                            } catch (RemoteException e) {
                                Slog.w(TAG, "Failed to report onError status: ", e);
                            }
                        },
                        VALIDATION_TIMEOUT_MILLIS,
                        VALIDATION_TIMEOUT_MILLIS,
                        TimeUnit.MILLISECONDS);
                        TimeUnit.MILLISECONDS);
                service.detectFromDspSource(
                service.detectFromDspSource(