diff --git a/services/autofill/java/com/android/server/autofill/FillRequestEventLogger.java b/services/autofill/java/com/android/server/autofill/FillRequestEventLogger.java index 3b30af69d02bd..06a616c3f3487 100644 --- a/services/autofill/java/com/android/server/autofill/FillRequestEventLogger.java +++ b/services/autofill/java/com/android/server/autofill/FillRequestEventLogger.java @@ -74,6 +74,9 @@ public final class FillRequestEventLogger { public static final int TRIGGER_REASON_SERVED_FROM_CACHED_RESPONSE = AUTOFILL_FILL_REQUEST_REPORTED__REQUEST_TRIGGER_REASON__TRIGGER_REASON_SERVED_FROM_CACHED_RESPONSE; + // Augmented autofill currently doesn't have an assigned request_id, use -2 as the magic number. + public static final int AUGMENTED_AUTOFILL_REQUEST_ID = -2; + private final int mSessionId; private Optional mEventInternal; @@ -102,6 +105,7 @@ public final class FillRequestEventLogger { /** * Set request_id as long as mEventInternal presents. + * For the case of Augmented Autofill, set to -2. */ public void maybeSetRequestId(int requestId) { mEventInternal.ifPresent(event -> event.mRequestId = requestId); diff --git a/services/autofill/java/com/android/server/autofill/FillResponseEventLogger.java b/services/autofill/java/com/android/server/autofill/FillResponseEventLogger.java new file mode 100644 index 0000000000000..6b8246cd5bfb1 --- /dev/null +++ b/services/autofill/java/com/android/server/autofill/FillResponseEventLogger.java @@ -0,0 +1,388 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.autofill; + +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DISPLAY_PRESENTATION_TYPE__UNKNOWN_AUTOFILL_DISPLAY_PRESENTATION_TYPE; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DISPLAY_PRESENTATION_TYPE__MENU; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DISPLAY_PRESENTATION_TYPE__INLINE; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DISPLAY_PRESENTATION_TYPE__DIALOG; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_TYPE__AUTHENTICATION_TYPE_UNKNOWN; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_TYPE__DATASET_AUTHENTICATION; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_TYPE__FULL_AUTHENTICATION; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_RESULT_UNKNOWN; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_SUCCESS; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_FAILURE; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__RESPONSE_STATUS__RESPONSE_STATUS_CANCELLED; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__RESPONSE_STATUS__RESPONSE_STATUS_FAILURE; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__RESPONSE_STATUS__RESPONSE_STATUS_SESSION_DESTROYED; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__RESPONSE_STATUS__RESPONSE_STATUS_SUCCESS; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__RESPONSE_STATUS__RESPONSE_STATUS_TIMEOUT; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__RESPONSE_STATUS__RESPONSE_STATUS_UNKNOWN; +import static com.android.server.autofill.Helper.sVerbose; + +import android.annotation.IntDef; +import android.annotation.Nullable; +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.PackageManager; +import android.provider.Settings; +import android.service.autofill.Dataset; +import android.text.TextUtils; +import android.util.Slog; +import android.view.autofill.AutofillId; + +import com.android.internal.util.FrameworkStatsLog; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.List; +import java.util.Optional; + +/** + * Helper class to log Autofill FillResponse stats. + */ +public final class FillResponseEventLogger { + private static final String TAG = "FillResponseEventLogger"; + + /** + * Reasons why presentation was not shown. These are wrappers around + * {@link com.android.os.AtomsProto.AutofillFillRequestReported.RequestTriggerReason}. + */ + @IntDef(prefix = {"DISPLAY_PRESENTATION_TYPE"}, value = { + DISPLAY_PRESENTATION_TYPE_UNKNOWN, + DISPLAY_PRESENTATION_TYPE_MENU, + DISPLAY_PRESENTATION_TYPE_INLINE, + DISPLAY_PRESENTATION_TYPE_DIALOG + }) + @Retention(RetentionPolicy.SOURCE) + public @interface DisplayPresentationType { + } + + /** + * Reasons why presentation was not shown. These are wrappers around + * {@link com.android.os.AtomsProto.AutofillFillResponseReported.AuthenticationType}. + */ + @IntDef(prefix = {"AUTHENTICATION_TYPE"}, value = { + AUTHENTICATION_TYPE_UNKNOWN, + AUTHENTICATION_TYPE_DATASET_AHTHENTICATION, + AUTHENTICATION_TYPE_FULL_AHTHENTICATION + }) + @Retention(RetentionPolicy.SOURCE) + public @interface AuthenticationType { + } + + /** + * Reasons why presentation was not shown. These are wrappers around + * {@link com.android.os.AtomsProto.AutofillFillResponseReported.FillResponseStatus}. + */ + @IntDef(prefix = {"RESPONSE_STATUS"}, value = { + RESPONSE_STATUS_UNKNOWN, + RESPONSE_STATUS_FAILURE, + RESPONSE_STATUS_SUCCESS, + RESPONSE_STATUS_CANCELLED, + RESPONSE_STATUS_TIMEOUT, + RESPONSE_STATUS_SESSION_DESTROYED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ResponseStatus { + } + + + /** + * Reasons why presentation was not shown. These are wrappers around + * {@link com.android.os.AtomsProto.AutofillFillResponseReported.AuthenticationResult}. + */ + @IntDef(prefix = {"AUTHENTICATION_RESULT"}, value = { + AUTHENTICATION_RESULT_UNKNOWN, + AUTHENTICATION_RESULT_SUCCESS, + AUTHENTICATION_RESULT_FAILURE + }) + @Retention(RetentionPolicy.SOURCE) + public @interface AuthenticationResult { + } + + public static final int DISPLAY_PRESENTATION_TYPE_UNKNOWN = + AUTOFILL_FILL_RESPONSE_REPORTED__DISPLAY_PRESENTATION_TYPE__UNKNOWN_AUTOFILL_DISPLAY_PRESENTATION_TYPE; + public static final int DISPLAY_PRESENTATION_TYPE_MENU = + AUTOFILL_FILL_RESPONSE_REPORTED__DISPLAY_PRESENTATION_TYPE__MENU; + public static final int DISPLAY_PRESENTATION_TYPE_INLINE = + AUTOFILL_FILL_RESPONSE_REPORTED__DISPLAY_PRESENTATION_TYPE__INLINE; + public static final int DISPLAY_PRESENTATION_TYPE_DIALOG = + AUTOFILL_FILL_RESPONSE_REPORTED__DISPLAY_PRESENTATION_TYPE__DIALOG; + public static final int AUTHENTICATION_TYPE_UNKNOWN = + AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_TYPE__AUTHENTICATION_TYPE_UNKNOWN; + public static final int AUTHENTICATION_TYPE_DATASET_AHTHENTICATION = + AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_TYPE__DATASET_AUTHENTICATION; + public static final int AUTHENTICATION_TYPE_FULL_AHTHENTICATION = + AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_TYPE__FULL_AUTHENTICATION; + + public static final int AUTHENTICATION_RESULT_UNKNOWN = + AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_RESULT_UNKNOWN; + public static final int AUTHENTICATION_RESULT_SUCCESS = + AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_SUCCESS; + public static final int AUTHENTICATION_RESULT_FAILURE = + AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_FAILURE; + public static final int RESPONSE_STATUS_TIMEOUT = + AUTOFILL_FILL_RESPONSE_REPORTED__RESPONSE_STATUS__RESPONSE_STATUS_TIMEOUT; + public static final int RESPONSE_STATUS_CANCELLED = + AUTOFILL_FILL_RESPONSE_REPORTED__RESPONSE_STATUS__RESPONSE_STATUS_CANCELLED; + public static final int RESPONSE_STATUS_FAILURE = + AUTOFILL_FILL_RESPONSE_REPORTED__RESPONSE_STATUS__RESPONSE_STATUS_FAILURE; + public static final int RESPONSE_STATUS_SESSION_DESTROYED = + AUTOFILL_FILL_RESPONSE_REPORTED__RESPONSE_STATUS__RESPONSE_STATUS_SESSION_DESTROYED; + public static final int RESPONSE_STATUS_SUCCESS = + AUTOFILL_FILL_RESPONSE_REPORTED__RESPONSE_STATUS__RESPONSE_STATUS_SUCCESS; + public static final int RESPONSE_STATUS_UNKNOWN = + AUTOFILL_FILL_RESPONSE_REPORTED__RESPONSE_STATUS__RESPONSE_STATUS_UNKNOWN; + + // Log a magic number when FillRequest failed or timeout to differentiate with FillRequest + // succeeded. + public static final int AVAILABLE_COUNT_WHEN_FILL_REQUEST_FAILED_OR_TIMEOUT = -1; + + private final int mSessionId; + private Optional mEventInternal; + + private FillResponseEventLogger(int sessionId) { + mSessionId = sessionId; + mEventInternal = Optional.empty(); + } + + /** + * A factory constructor to create FillResponseEventLogger. + */ + public static FillResponseEventLogger forSessionId(int sessionId) { + return new FillResponseEventLogger(sessionId); + } + + /** + * Reset mEventInternal before logging for a new response. It shall be called + * for each FillResponse. + */ + public void startLogForNewResponse() { + if (!mEventInternal.isEmpty()) { + Slog.w(TAG, "FillResponseEventLogger is not empty before starting " + + "for a new request"); + } + mEventInternal = Optional.of(new FillResponseEventInternal()); + } + + /** + * Set request_id as long as mEventInternal presents. + */ + public void maybeSetRequestId(int val) { + mEventInternal.ifPresent(event -> event.mRequestId = val); + } + + /** + * Set app_package_uid as long as mEventInternal presents. + */ + public void maybeSetAppPackageUid(int val) { + mEventInternal.ifPresent(event -> { + event.mAppPackageUid = val; + }); + } + + /** + * Set display_presentation_type as long as mEventInternal presents. + */ + public void maybeSetDisplayPresentationType(@DisplayPresentationType int val) { + mEventInternal.ifPresent(event -> { + event.mDisplayPresentationType = val; + }); + } + + /** + * Set available_count as long as mEventInternal presents. + * For cases of FillRequest failed and timeout, set to -1. + */ + public void maybeSetAvailableCount(@Nullable List datasetList, + AutofillId currentViewId) { + mEventInternal.ifPresent(event -> { + int availableCount = getDatasetCountForAutofillId(datasetList, currentViewId); + event.mAvailableCount = availableCount; + }); + } + + public void maybeSetAvailableCount(int val) { + mEventInternal.ifPresent(event -> { + event.mAvailableCount = val; + }); + } + + private static int getDatasetCountForAutofillId(@Nullable List datasetList, + AutofillId currentViewId) { + int availableCount = 0; + if (datasetList != null) { + for (int i = 0; i < datasetList.size(); i++) { + Dataset data = datasetList.get(i); + if (data != null && data.getFieldIds() != null + && data.getFieldIds().contains(currentViewId)) { + availableCount += 1; + } + } + } + return availableCount; + } + + /** + * Set save_ui_trigger_ids as long as mEventInternal presents. + */ + public void maybeSetSaveUiTriggerIds(int val) { + mEventInternal.ifPresent(event -> { + event.mSaveUiTriggerIds = val; + }); + } + + /** + * Set latency_fill_response_received_millis as long as mEventInternal presents. + */ + public void maybeSetLatencyFillResponseReceivedMillis(int val) { + mEventInternal.ifPresent(event -> { + event.mLatencyFillResponseReceivedMillis = val; + }); + } + + /** + * Set authentication_type as long as mEventInternal presents. + */ + public void maybeSetAuthenticationType(@AuthenticationType int val) { + mEventInternal.ifPresent(event -> { + event.mAuthenticationType = val; + }); + } + + /** + * Set authentication_result as long as mEventInternal presents. + */ + public void maybeSetAuthenticationResult(@AuthenticationResult int val) { + mEventInternal.ifPresent(event -> { + event.mAuthenticationResult = val; + }); + } + + /** + * Set authentication_failure_reason as long as mEventInternal presents. + */ + public void maybeSetAuthenticationFailureReason(int val) { + mEventInternal.ifPresent(event -> { + event.mAuthenticationFailureReason = val; + }); + } + + /** + * Set latency_authentication_ui_display_millis as long as mEventInternal presents. + */ + public void maybeSetLatencyAuthenticationUiDisplayMillis(int val) { + mEventInternal.ifPresent(event -> { + event.mLatencyAuthenticationUiDisplayMillis = val; + }); + } + + /** + * Set latency_dataset_display_millis as long as mEventInternal presents. + */ + public void maybeSetLatencyDatasetDisplayMillis(int val) { + mEventInternal.ifPresent(event -> { + event.mLatencyDatasetDisplayMillis = val; + }); + } + + /** + * Set response_status as long as mEventInternal presents. + */ + public void maybeSetResponseStatus(@ResponseStatus int val) { + mEventInternal.ifPresent(event -> { + event.mResponseStatus = val; + }); + } + + /** + * Set latency_response_processing_millis as long as mEventInternal presents. + */ + public void maybeSetLatencyResponseProcessingMillis(int val) { + mEventInternal.ifPresent(event -> { + event.mLatencyResponseProcessingMillis = val; + }); + } + + + /** + * Log an AUTOFILL_FILL_RESPONSE_REPORTED event. + */ + public void logAndEndEvent() { + if (!mEventInternal.isPresent()) { + Slog.w(TAG, "Shouldn't be logging AutofillFillRequestReported again for same " + + "event"); + return; + } + FillResponseEventInternal event = mEventInternal.get(); + if (sVerbose) { + Slog.v(TAG, "Log AutofillFillResponseReported:" + + " requestId=" + event.mRequestId + + " sessionId=" + mSessionId + + " mAppPackageUid=" + event.mAppPackageUid + + " mDisplayPresentationType=" + event.mDisplayPresentationType + + " mAvailableCount=" + event.mAvailableCount + + " mSaveUiTriggerIds=" + event.mSaveUiTriggerIds + + " mLatencyFillResponseReceivedMillis=" + event.mLatencyFillResponseReceivedMillis + + " mAuthenticationType=" + event.mAuthenticationType + + " mAuthenticationResult=" + event.mAuthenticationResult + + " mAuthenticationFailureReason=" + event.mAuthenticationFailureReason + + " mLatencyAuthenticationUiDisplayMillis=" + event.mLatencyAuthenticationUiDisplayMillis + + " mLatencyDatasetDisplayMillis=" + event.mLatencyDatasetDisplayMillis + + " mResponseStatus=" + event.mResponseStatus + + " mLatencyResponseProcessingMillis=" + event.mLatencyResponseProcessingMillis); + } + FrameworkStatsLog.write( + AUTOFILL_FILL_RESPONSE_REPORTED, + event.mRequestId, + mSessionId, + event.mAppPackageUid, + event.mDisplayPresentationType, + event.mAvailableCount, + event.mSaveUiTriggerIds, + event.mLatencyFillResponseReceivedMillis, + event.mAuthenticationType, + event.mAuthenticationResult, + event.mAuthenticationFailureReason, + event.mLatencyAuthenticationUiDisplayMillis, + event.mLatencyDatasetDisplayMillis, + event.mResponseStatus, + event.mLatencyResponseProcessingMillis); + mEventInternal = Optional.empty(); + } + + private static final class FillResponseEventInternal { + int mRequestId = -1; + int mAppPackageUid = -1; + int mDisplayPresentationType = DISPLAY_PRESENTATION_TYPE_UNKNOWN; + int mAvailableCount = 0; + int mSaveUiTriggerIds = -1; + int mLatencyFillResponseReceivedMillis = 0; + int mAuthenticationType = AUTHENTICATION_TYPE_UNKNOWN; + int mAuthenticationResult = AUTHENTICATION_RESULT_UNKNOWN; + int mAuthenticationFailureReason = -1; + int mLatencyAuthenticationUiDisplayMillis = 0; + int mLatencyDatasetDisplayMillis = 0; + int mResponseStatus = RESPONSE_STATUS_UNKNOWN; + int mLatencyResponseProcessingMillis = 0; + + FillResponseEventInternal() { + } + } +} diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 4acdabec92f49..4af6b89eb9397 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -41,9 +41,16 @@ import static android.view.autofill.AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM import static android.view.autofill.AutofillManager.getSmartSuggestionModeToString; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; +import static com.android.server.autofill.FillRequestEventLogger.AUGMENTED_AUTOFILL_REQUEST_ID; import static com.android.server.autofill.FillRequestEventLogger.TRIGGER_REASON_NORMAL_TRIGGER; import static com.android.server.autofill.FillRequestEventLogger.TRIGGER_REASON_PRE_TRIGGER; import static com.android.server.autofill.FillRequestEventLogger.TRIGGER_REASON_SERVED_FROM_CACHED_RESPONSE; +import static com.android.server.autofill.FillResponseEventLogger.AVAILABLE_COUNT_WHEN_FILL_REQUEST_FAILED_OR_TIMEOUT; +import static com.android.server.autofill.FillResponseEventLogger.RESPONSE_STATUS_FAILURE; +import static com.android.server.autofill.FillResponseEventLogger.RESPONSE_STATUS_SUCCESS; +import static com.android.server.autofill.FillResponseEventLogger.RESPONSE_STATUS_FAILURE; +import static com.android.server.autofill.FillResponseEventLogger.RESPONSE_STATUS_TIMEOUT; +import static com.android.server.autofill.FillResponseEventLogger.RESPONSE_STATUS_SESSION_DESTROYED; import static com.android.server.autofill.Helper.containsCharsInOrder; import static com.android.server.autofill.Helper.createSanitizers; import static com.android.server.autofill.Helper.getNumericValue; @@ -446,6 +453,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState @GuardedBy("mLock") private FillRequestEventLogger mFillRequestEventLogger; + @NonNull + @GuardedBy("mLock") + private FillResponseEventLogger mFillResponseEventLogger; + /** * Fill dialog request would likely be sent slightly later. */ @@ -1122,8 +1133,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState + ", flags=" + flags + ")"); } mSessionFlags.mAugmentedAutofillOnly = true; - // Augmented autofill doesn't have request_id. - mFillRequestEventLogger.maybeSetRequestId(-1); + mFillRequestEventLogger.maybeSetRequestId(AUGMENTED_AUTOFILL_REQUEST_ID); mFillRequestEventLogger.maybeSetIsAugmented(mSessionFlags.mAugmentedAutofillOnly); mFillRequestEventLogger.logAndEndEvent(); triggerAugmentedAutofillLocked(flags); @@ -1315,6 +1325,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mSessionState = STATE_ACTIVE; mPresentationStatsEventLogger = PresentationStatsEventLogger.forSessionId(sessionId); mFillRequestEventLogger = FillRequestEventLogger.forSessionId(sessionId); + mFillResponseEventLogger = FillResponseEventLogger.forSessionId(sessionId); synchronized (mLock) { mSessionFlags = new SessionFlags(); mSessionFlags.mAugmentedAutofillOnly = forAugmentedAutofillOnly; @@ -1421,24 +1432,35 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // FillServiceCallbacks @Override + @SuppressWarnings("GuardedBy") public void onFillRequestSuccess(int requestId, @Nullable FillResponse response, @NonNull String servicePackageName, int requestFlags) { final AutofillId[] fieldClassificationIds; final LogMaker requestLog; + // Start a new FillResponse logger for the success case. + mFillResponseEventLogger.startLogForNewResponse(); + mFillResponseEventLogger.maybeSetRequestId(requestId); + mFillResponseEventLogger.maybeSetAppPackageUid(uid); + mFillResponseEventLogger.maybeSetResponseStatus(RESPONSE_STATUS_SUCCESS); + // Time passed since session was created + final long fillRequestReceivedRelativeTimestamp = + SystemClock.elapsedRealtime() - mLatencyBaseTime; + mPresentationStatsEventLogger.maybeSetFillResponseReceivedTimestampMs( + (int) (fillRequestReceivedRelativeTimestamp)); + mFillResponseEventLogger.maybeSetLatencyFillResponseReceivedMillis( + (int) (fillRequestReceivedRelativeTimestamp)); + synchronized (mLock) { if (mDestroyed) { Slog.w(TAG, "Call to Session#onFillRequestSuccess() rejected - session: " + id + " destroyed"); + mFillResponseEventLogger.maybeSetResponseStatus(RESPONSE_STATUS_SESSION_DESTROYED); + mFillResponseEventLogger.logAndEndEvent(); return; } - // Time passed since session was created - final long fillRequestReceivedRelativeTimestamp = - SystemClock.elapsedRealtime() - mLatencyBaseTime; - mPresentationStatsEventLogger.maybeSetFillResponseReceivedTimestampMs( - (int) (fillRequestReceivedRelativeTimestamp)); requestLog = mRequestLogs.get(requestId); if (requestLog != null) { @@ -1844,11 +1866,23 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // fallback to the default platform password manager mSessionFlags.mClientSuggestionsEnabled = false; mLastFillDialogTriggerIds = null; + // Log the existing FillResponse event. + mFillResponseEventLogger.logAndEndEvent(); final InlineSuggestionsRequest inlineRequest = (mLastInlineSuggestionsRequest != null && mLastInlineSuggestionsRequest.first == requestId) ? mLastInlineSuggestionsRequest.second : null; + + // Start a new FillRequest logger for client suggestion fallback. + mFillRequestEventLogger.startLogForNewRequest(); + mFillRequestEventLogger.maybeSetAppPackageUid(uid); + mFillRequestEventLogger.maybeSetFlags( + flags & ~FLAG_ENABLED_CLIENT_SUGGESTIONS); + mFillRequestEventLogger.maybeSetRequestTriggerReason( + TRIGGER_REASON_NORMAL_TRIGGER); + mFillRequestEventLogger.maybeSetIsClientSuggestionFallback(true); + mAssistReceiver.newAutofillRequestLocked(inlineRequest); requestAssistStructureLocked(requestId, flags & ~FLAG_ENABLED_CLIENT_SUGGESTIONS); @@ -1857,24 +1891,42 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // FillServiceCallbacks @Override + @SuppressWarnings("GuardedBy") public void onFillRequestFailure(int requestId, @Nullable CharSequence message) { onFillRequestFailureOrTimeout(requestId, false, message); } // FillServiceCallbacks @Override + @SuppressWarnings("GuardedBy") public void onFillRequestTimeout(int requestId) { onFillRequestFailureOrTimeout(requestId, true, null); } + @SuppressWarnings("GuardedBy") private void onFillRequestFailureOrTimeout(int requestId, boolean timedOut, @Nullable CharSequence message) { boolean showMessage = !TextUtils.isEmpty(message); + + // Start a new FillResponse logger for the failure or timeout case. + mFillResponseEventLogger.startLogForNewResponse(); + mFillResponseEventLogger.maybeSetRequestId(requestId); + mFillResponseEventLogger.maybeSetAppPackageUid(uid); + mFillResponseEventLogger.maybeSetAvailableCount( + AVAILABLE_COUNT_WHEN_FILL_REQUEST_FAILED_OR_TIMEOUT); + final long fillRequestReceivedRelativeTimestamp = + SystemClock.elapsedRealtime() - mLatencyBaseTime; + mFillResponseEventLogger.maybeSetLatencyFillResponseReceivedMillis( + (int)(fillRequestReceivedRelativeTimestamp)); + synchronized (mLock) { unregisterDelayedFillBroadcastLocked(); if (mDestroyed) { Slog.w(TAG, "Call to Session#onFillRequestFailureOrTimeout(req=" + requestId + ") rejected - session: " + id + " destroyed"); + mFillResponseEventLogger.maybeSetResponseStatus(RESPONSE_STATUS_SESSION_DESTROYED); + mFillResponseEventLogger.logAndEndEvent(); + return; } if (sDebug) { @@ -1905,11 +1957,14 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState if (timedOut) { mPresentationStatsEventLogger.maybeSetNoPresentationEventReason( NOT_SHOWN_REASON_REQUEST_TIMEOUT); + mFillResponseEventLogger.maybeSetResponseStatus(RESPONSE_STATUS_TIMEOUT); } else { mPresentationStatsEventLogger.maybeSetNoPresentationEventReason( NOT_SHOWN_REASON_REQUEST_FAILED); + mFillResponseEventLogger.maybeSetResponseStatus(RESPONSE_STATUS_FAILURE); } mPresentationStatsEventLogger.logAndEndEvent(); + mFillResponseEventLogger.logAndEndEvent(); } notifyUnavailableToClient(AutofillManager.STATE_UNKNOWN_FAILED, /* autofillableIds= */ null); @@ -4455,7 +4510,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState Slog.w(TAG, "processNullResponseLocked(): no context for req " + requestId); autofillableIds = null; } - + // Log the existing FillResponse event. + mFillResponseEventLogger.logAndEndEvent(); mService.resetLastResponse(); // The default autofill service cannot fulfill the request, let's check if the augmented @@ -4560,6 +4616,12 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState + getSmartSuggestionModeToString(mode) + " when server returned null for session " + this.id); } + // Log FillRequest for Augmented Autofill. + mFillRequestEventLogger.startLogForNewRequest(); + mFillRequestEventLogger.maybeSetAppPackageUid(uid); + mFillRequestEventLogger.maybeSetFlags(mFlags); + mFillRequestEventLogger.maybeSetRequestId(AUGMENTED_AUTOFILL_REQUEST_ID); + mFillRequestEventLogger.logAndEndEvent(); final ViewState viewState = mViewStates.get(mCurrentViewId); viewState.setState(ViewState.STATE_TRIGGERED_AUGMENTED_AUTOFILL); @@ -4677,6 +4739,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mPresentationStatsEventLogger.maybeSetAvailableCount( newResponse.getDatasets(), mCurrentViewId); + mFillResponseEventLogger.maybeSetAvailableCount( + newResponse.getDatasets(), mCurrentViewId); setViewStatesLocked(newResponse, ViewState.STATE_FILLABLE, false); updateFillDialogTriggerIdsLocked();