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

Commit 0cf35e85 authored by Nicholas Ambur's avatar Nicholas Ambur
Browse files

Add Logging of the UI Latency for hotword invocation

Log the UI latency with UIActionLatencyReported atom. We plan to
calulate the latency from when the SoundTrigger HAL emits an event to
when the VoiceInteraction system UI view is shown.

Test: device_config put latency_tracker enabled true; verify traces
and latency is logged in WW.
Bug: 247879896

Change-Id: I3edb91691e81f8f23660c0823a6388338fe926ad
parent 454b033e
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPOR
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_SENSOR;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_BACK_ARROW;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_SELECTION_TOOLBAR;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_VOICE_INTERACTION;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_START_RECENTS_ANIMATION;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SWITCH_DISPLAY_UNFOLD;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_TOGGLE_RECENTS;
@@ -174,6 +175,12 @@ public class LatencyTracker {
     */
    public static final int ACTION_FOLD_TO_AOD = 18;

    /**
     * Time it takes to show the {@link android.service.voice.VoiceInteractionSession} system UI
     * after a {@link android.hardware.soundtrigger3.ISoundTriggerHw} voice trigger.
     */
    public static final int ACTION_SHOW_VOICE_INTERACTION = 19;

    private static final int[] ACTIONS_ALL = {
        ACTION_EXPAND_PANEL,
        ACTION_TOGGLE_RECENTS,
@@ -194,6 +201,7 @@ public class LatencyTracker {
        ACTION_LOAD_SHARE_SHEET,
        ACTION_SHOW_SELECTION_TOOLBAR,
        ACTION_FOLD_TO_AOD,
        ACTION_SHOW_VOICE_INTERACTION,
    };

    /** @hide */
@@ -217,6 +225,7 @@ public class LatencyTracker {
        ACTION_LOAD_SHARE_SHEET,
        ACTION_SHOW_SELECTION_TOOLBAR,
        ACTION_FOLD_TO_AOD,
        ACTION_SHOW_VOICE_INTERACTION,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface Action {
@@ -243,6 +252,7 @@ public class LatencyTracker {
            UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOAD_SHARE_SHEET,
            UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_SELECTION_TOOLBAR,
            UIACTION_LATENCY_REPORTED__ACTION__ACTION_FOLD_TO_AOD,
            UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_VOICE_INTERACTION,
    };

    private static LatencyTracker sLatencyTracker;
@@ -340,6 +350,8 @@ public class LatencyTracker {
                return "ACTION_SHOW_SELECTION_TOOLBAR";
            case UIACTION_LATENCY_REPORTED__ACTION__ACTION_FOLD_TO_AOD:
                return "ACTION_FOLD_TO_AOD";
            case UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_VOICE_INTERACTION:
                return "ACTION_SHOW_VOICE_INTERACTION";
            default:
                throw new IllegalArgumentException("Invalid action");
        }
+28 −1
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.soundtrigger_middleware;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.media.permission.Identity;
import android.media.permission.IdentityContext;
import android.media.soundtrigger.ModelParameterRange;
@@ -33,6 +34,8 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

import com.android.internal.util.LatencyTracker;

import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
@@ -65,9 +68,12 @@ import java.util.Objects;
public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareInternal, Dumpable {
    private static final String TAG = "SoundTriggerMiddlewareLogging";
    private final @NonNull ISoundTriggerMiddlewareInternal mDelegate;
    private final @NonNull Context mContext;

    public SoundTriggerMiddlewareLogging(@NonNull ISoundTriggerMiddlewareInternal delegate) {
    public SoundTriggerMiddlewareLogging(@NonNull Context context,
            @NonNull ISoundTriggerMiddlewareInternal delegate) {
        mDelegate = delegate;
        mContext = context;
    }

    @Override
@@ -298,6 +304,7 @@ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareInt
                    int captureSession)
                    throws RemoteException {
                try {
                    startKeyphraseEventLatencyTracking(event);
                    mCallbackDelegate.onPhraseRecognition(modelHandle, event, captureSession);
                    logVoidReturn("onPhraseRecognition", modelHandle, event);
                } catch (Exception e) {
@@ -347,6 +354,26 @@ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareInt
                logVoidReturnWithObject(this, mOriginatorIdentity, methodName, args);
            }

            /**
             * Starts the latency tracking log for keyphrase hotword invocation.
             * The measurement covers from when the SoundTrigger HAL emits an event to when the
             * {@link android.service.voice.VoiceInteractionSession} system UI view is shown.
             */
            private void startKeyphraseEventLatencyTracking(PhraseRecognitionEvent event) {
                String latencyTrackerTag = null;
                if (event.phraseExtras.length > 0) {
                    latencyTrackerTag = "KeyphraseId=" + event.phraseExtras[0].id;
                }
                LatencyTracker latencyTracker = LatencyTracker.getInstance(mContext);
                // To avoid adding cancel to all of the different failure modes between here and
                // showing the system UI, we defensively cancel once.
                // Either we hit the LatencyTracker timeout of 15 seconds or we defensively cancel
                // here if any error occurs.
                latencyTracker.onActionCancel(LatencyTracker.ACTION_SHOW_VOICE_INTERACTION);
                latencyTracker.onActionStart(LatencyTracker.ACTION_SHOW_VOICE_INTERACTION,
                        latencyTrackerTag);
            }

            @Override
            public IBinder asBinder() {
                return mCallbackDelegate.asBinder();
+11 −10
Original line number Diff line number Diff line
@@ -20,14 +20,14 @@ import static android.Manifest.permission.SOUNDTRIGGER_DELEGATE_IDENTITY;

import android.annotation.NonNull;
import android.content.Context;
import android.media.soundtrigger.ModelParameterRange;
import android.media.soundtrigger.PhraseSoundModel;
import android.media.soundtrigger.RecognitionConfig;
import android.media.soundtrigger.SoundModel;
import android.media.permission.ClearCallingIdentityContext;
import android.media.permission.Identity;
import android.media.permission.PermissionUtil;
import android.media.permission.SafeCloseable;
import android.media.soundtrigger.ModelParameterRange;
import android.media.soundtrigger.PhraseSoundModel;
import android.media.soundtrigger.RecognitionConfig;
import android.media.soundtrigger.SoundModel;
import android.media.soundtrigger_middleware.ISoundTriggerCallback;
import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService;
import android.media.soundtrigger_middleware.ISoundTriggerModule;
@@ -226,7 +226,8 @@ public class SoundTriggerMiddlewareService extends ISoundTriggerMiddlewareServic
            HalFactory[] factories = new HalFactory[]{new DefaultHalFactory()};

            publishBinderService(Context.SOUND_TRIGGER_MIDDLEWARE_SERVICE,
                    new SoundTriggerMiddlewareService(new SoundTriggerMiddlewareLogging(
                    new SoundTriggerMiddlewareService(
                            new SoundTriggerMiddlewareLogging(getContext(),
                                new SoundTriggerMiddlewarePermission(
                                        new SoundTriggerMiddlewareValidation(
                                                new SoundTriggerMiddlewareImpl(factories,
+35 −0
Original line number Diff line number Diff line
@@ -95,6 +95,7 @@ import com.android.internal.app.IVoiceInteractor;
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.LatencyTracker;
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -191,6 +192,8 @@ public class VoiceInteractionManagerService extends SystemService {
            mSoundTriggerInternal = LocalServices.getService(SoundTriggerInternal.class);
        } else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
            mServiceStub.systemRunning(isSafeMode());
        } else if (phase == PHASE_BOOT_COMPLETED) {
            mServiceStub.registerVoiceInteractionSessionListener(mLatencyLoggingListener);
        }
    }

@@ -2334,4 +2337,36 @@ public class VoiceInteractionManagerService extends SystemService {
            }
        };
    }

    /**
     * End the latency tracking log for keyphrase hotword invocation.
     * The measurement covers from when the SoundTrigger HAL emits an event, captured in
     * {@link com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging}
     * to when the {@link android.service.voice.VoiceInteractionSession} system UI view is shown.
     */
    private final IVoiceInteractionSessionListener mLatencyLoggingListener =
            new IVoiceInteractionSessionListener.Stub() {
                @Override
                public void onVoiceSessionShown() throws RemoteException {}

                @Override
                public void onVoiceSessionHidden() throws RemoteException {}

                @Override
                public void onVoiceSessionWindowVisibilityChanged(boolean visible)
                        throws RemoteException {
                    if (visible) {
                        LatencyTracker.getInstance(mContext)
                                .onActionEnd(LatencyTracker.ACTION_SHOW_VOICE_INTERACTION);
                    }
                }

                @Override
                public void onSetUiHints(Bundle args) throws RemoteException {}

                @Override
                public IBinder asBinder() {
                    return mServiceStub;
                }
            };
}