Merge "Merged many autofill session metrics into AUTOFILL_REQUEST:"
diff --git a/core/java/android/service/autofill/FillCallback.java b/core/java/android/service/autofill/FillCallback.java
index 105cd38..0257891 100644
--- a/core/java/android/service/autofill/FillCallback.java
+++ b/core/java/android/service/autofill/FillCallback.java
@@ -70,7 +70,7 @@
         assertNotCalled();
         mCalled = true;
         try {
-            mCallback.onFailure(message);
+            mCallback.onFailure(mRequestId, message);
         } catch (RemoteException e) {
             e.rethrowAsRuntimeException();
         }
diff --git a/core/java/android/service/autofill/IFillCallback.aidl b/core/java/android/service/autofill/IFillCallback.aidl
index 2bb3e9a..1bad1d7 100644
--- a/core/java/android/service/autofill/IFillCallback.aidl
+++ b/core/java/android/service/autofill/IFillCallback.aidl
@@ -28,5 +28,5 @@
 interface IFillCallback {
     void onCancellable(in ICancellationSignal cancellation);
     void onSuccess(in FillResponse response);
-    void onFailure(CharSequence message);
+    void onFailure(int requestId, CharSequence message);
 }
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index c67a9f8..52a68b0 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3986,27 +3986,40 @@
     // OS: O
     APP_TRANSITION_IS_EPHEMERAL = 905;
 
-    // An autofill session was started
+    // An autofill session was started.
+    // OS: O
     // Package: Package of app that is autofilled
     // NOTE: starting on OS MR1, it also added the following field:
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // NOTE: starting on OS P, it also added the following field:
-    // Tag FIELD_FLAGS - Flags used to start the session
+    // Tag FIELD_AUTOFIL_FLAGS - Flags used to start the session
     // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_SESSION_STARTED = 906;
 
     // An autofill request was processed by a service
-    // Type TYPE_SUCCESS: The request succeeded
-    // Type TYPE_FAILURE: The request failed
+    // Type TYPE_SUCCESS: service called FillCalback.onSuccess()
+    // Type TYPE_FAILURE: service called FillCallback.onFailure()
     // Package: Package of app that is autofilled
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // Tag FIELD_AUTOFILL_NUM_DATASETS: The number of datasets returned in the response, or -1 if
-    // the service returned a null response.
-    // NOTE: starting on OS P, it also added:
-    // Type TYPE_CLOSE: Service returned a null response.
+    // the service returned a null response
+    // NOTE: starting on OS P, it also added the following fields:
+    // TYPE_CLOSE: request timed out before service called a FillCallback method
+    // Tag FIELD_AUTOFILL_REQUEST_ORDINAL: sequence number of the request inside a session; starts
+    //     with 1.
+    // Tag FIELD_AUTOFILL_FLAGS: flags used to request autofill
+    // Tag FIELD_AUTOFILL_DURATION: how long it took (in ms) to show the autofill UI after a field
+    //     was focused.
+    // Tag FIELD_AUTOFILL_AUTHENTICATION_STATUS: status of authenticated datasets or responses.
     // Tag FIELD_AUTOFILL_NUM_FIELD_CLASSIFICATION_IDS: if service requested field classification,
-    // number of entries field ids in the request.
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    //     number of entries field ids in the request.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: Prior to P, some of the fields above were logged by 5 different metrics:
+    // - AUTOFILL_UI_LATENCY
+    // - AUTOFILL_AUTHENTICATED;
+    // - AUTOFILL_DATASET_AUTHENTICATED
+    // - AUTOFILL_INVALID_AUTHENTICATION
+    // - AUTOFILL_INVALID_DATASET_AUTHENTICATION
     AUTOFILL_REQUEST = 907;
 
     // Tag of a field for a package of an autofill service
@@ -4025,7 +4038,7 @@
     // Tag FIELD_AUTOFILL_NUM_DATASETS: The number of datasets shown
     // NOTE: starting on OS P, it also added the following field:
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_FILL_UI = 910;
 
     // Tag of a field for the length of the filter text
@@ -4034,8 +4047,7 @@
     // An autofill authentication succeeded
     // Package: Package of app that was autofilled
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: starting on OS P, this metric became a value for FIELD_AUTOFILL_AUTHENTICATION_STATUS
     AUTOFILL_AUTHENTICATED = 912;
 
     // An activity was autofilled and all values could be applied
@@ -4043,7 +4055,7 @@
     // Tag FIELD_AUTOFILL_NUM_VALUES: Number of values that were suggested to be autofilled
     // Tag FIELD_AUTOFILL_NUM_VIEWS_FILLED: Number of views that could be filled
     // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_DATASET_APPLIED = 913;
 
     // Tag of a field for the number values to be filled in
@@ -4060,26 +4072,30 @@
     // Tag FIELD_AUTOFILL_NUM_IDS: The number of ids that are saved
     // NOTE: starting on OS P, it also added the following field:
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_SAVE_UI = 916;
 
     // Tag of a field for the number of saveable ids
     FIELD_AUTOFILL_NUM_IDS = 917;
 
-    // ACTION: An autofill service was reqiested to save data
+    // ACTION: An autofill service was requested to save data
     // Type TYPE_SUCCESS: The request succeeded right away
     // Type TYPE_OPEN: The request succeeded but the service launched an IntentSender
     // Type TYPE_FAILURE: The request failed
     // Package: Package of app that was autofilled
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_DATA_SAVE_REQUEST = 918;
 
     // An auto-fill session was finished
+    // OS: O
     // Package: Package of app that was autofilled
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: starting on OS P, it also added the following fields:
+    // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_NUMBER_REQUESTS: number of requests made to the service (each request
+    //     is logged by a separate AUTOFILL_REQUEST metric)
     AUTOFILL_SESSION_FINISHED = 919;
 
     // meta-event: a reader has checkpointed the log here.
@@ -4206,7 +4222,7 @@
     // Tag FIELD_AUTOFILL_SERVICE: Package of the autofill service that processed the request
     // TAG FIELD_AUTOFILL_FORGED_COMPONENT_NAME: Component name being forged
     // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_FORGED_COMPONENT_ATTEMPT = 948;
 
     // FIELD - The component that an app tried tro forged.
@@ -4665,7 +4681,7 @@
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // Tag FIELD_AUTOFILL_PREVIOUS_LENGTH: the previous length of the value
     // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_VALUE_RESET = 1124;
 
     // Tag of AUTOFILL_VALUE_RESET
@@ -4675,25 +4691,21 @@
     // An autofill dataset authentication succeeded
     // Package: Package of app that was autofilled
     // OS: O MR
-    // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: starting on OS P, this metric became a value for FIELD_AUTOFILL_AUTHENTICATION_STATUS
     AUTOFILL_DATASET_AUTHENTICATED = 1126;
 
     // An autofill service provided an invalid dataset authentication
     // Package: Package of app that was autofilled
     // OS: O MR
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: starting on OS P, this metric became a value for FIELD_AUTOFILL_AUTHENTICATION_STATUS
     AUTOFILL_INVALID_DATASET_AUTHENTICATION = 1127;
 
     // An autofill service provided an invalid authentication extra
     // Package: Package of app that was autofilled
     // OS: O MR
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: starting on OS P, this metric became a value for FIELD_AUTOFILL_AUTHENTICATION_STATUS
     AUTOFILL_INVALID_AUTHENTICATION = 1128;
 
     // An autofill service used a custom description (using RemoteViews) in the autofill save UI
@@ -4702,7 +4714,7 @@
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // Tag FIELD_AUTOFILL_SAVE_TYPE: Type of save object passed by the service
     // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_SAVE_CUSTOM_DESCRIPTION = 1129;
 
     // FIELD - Type of save object passed by the service when the Save UI is shown
@@ -4715,7 +4727,7 @@
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // Tag FIELD_AUTOFILL_SAVE_TYPE: Type of save object passed by the service
     // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_SAVE_CUSTOM_SUBTITLE = 1131;
 
     // User tapped a link in the custom description of the autofill save UI provided by an autofill service
@@ -4727,7 +4739,7 @@
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // Tag FIELD_AUTOFILL_SAVE_TYPE: Type of save object passed by the service
     // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_SAVE_LINK_TAPPED = 1132;
 
     // Result of the validation on save when an autofill service provided a validator
@@ -4739,7 +4751,7 @@
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // Tag FIELD_AUTOFILL_SAVE_TYPE: Type of save object passed by the service
     // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_SAVE_VALIDATION = 1133;
 
     // Result of an operation in the autofill save UI after the user tapped a link in the custom description
@@ -4750,7 +4762,7 @@
     // Type TYPE_DISMISS: The autofill save UI was destroyed
     // Type TYPE_FAILURE: An invalid opperation was reported by the app's AutofillManager
     // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_PENDING_SAVE_UI_OPERATION = 1134;
 
     // Autofill service called API that disables itself
@@ -4758,13 +4770,12 @@
     // OS: O MR
     AUTOFILL_SERVICE_DISABLED_SELF = 1135;
 
+    // DEPRECATED - on P it was merged with AUTOFILL_REQUEST
     // Reports how long it took to show the autofill UI after a field was focused
     // Tag FIELD_AUTOFILL_DURATION: Duration in ms
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // Package: Package of the autofill service
     // OS: O MR
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_UI_LATENCY = 1136;
 
     // Action: the snooze leave-behind was shown after the user clicked the snooze icon
@@ -4932,14 +4943,14 @@
     // Package: Package of app that is autofilled
     // OS: P
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_EXPLICIT_SAVE_TRIGGER_DEFINITION = 1228;
 
     // The autofill context was commited when the user clicked a view explicitly marked by the
     // service as committing it
     // Package: Package of app that is autofilled
     // OS: P
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_SAVE_EXPLICITLY_TRIGGERED = 1229;
 
     // OPEN: Settings > Network & Internet > Mobile network > Wi-Fi calling
@@ -4952,7 +4963,7 @@
     // OS: P
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // Tag FIELD_AUTOFILL_DURATION: duration (in ms) that autofill will be disabled
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_SERVICE_DISABLED_APP = 1231;
 
     // An autofill service asked to disable autofill for a given activity.
@@ -4961,7 +4972,7 @@
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // Tag FIELD_CLASS_NAME: Class name of the activity that is being disabled for autofill
     // Tag FIELD_AUTOFILL_DURATION: duration (in ms) that autofill will be disabled
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_SERVICE_DISABLED_ACTIVITY = 1232;
 
     // ACTION: Stop an app and turn on background check
@@ -5173,7 +5184,7 @@
     // OS: P
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // Tag FIELD_AUTOFILL_MATCH_SCORE: Average score of the matches, in the range of 0 to 100
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_FIELD_CLASSIFICATION_MATCHES = 1273;
 
     // Tag used to report autofill field classification scores
@@ -5840,6 +5851,7 @@
     ACTION_STORAGE_MIGRATE_LATER = 1413;
 
     // Tag used to report whether an activity is being autofilled  on compatibility mode.
+    // OS: P
     FIELD_AUTOFILL_COMPAT_MODE = 1414;
 
     // OPEN: Settings > Sound > Switch a2dp devices dialog
@@ -6045,6 +6057,28 @@
     // OS: P
     ACTION_BATTERY_CAUSED_SHUTDOWN = 1451;
 
+    // FIELD: Flags used on autofill-related metrics
+    // OS: P
+    FIELD_AUTOFILL_FLAGS = 1452;
+
+    // Tag used when the service returned an authenticated dataset or response.
+    // Used to replace the following individual metrics, which now are logged as the value of this
+    // field in the AUTOFILL_REQUEST metric:
+    // - AUTOFILL_AUTHENTICATED;
+    // - AUTOFILL_DATASET_AUTHENTICATED
+    // - AUTOFILL_INVALID_AUTHENTICATION
+    // - AUTOFILL_INVALID_DATASET_AUTHENTICATION
+    // OS: P
+    FIELD_AUTOFILL_AUTHENTICATION_STATUS = 1453;
+
+    // FIELD: Index of the autofill request inside of a session.
+    // OS: P
+    FIELD_AUTOFILL_REQUEST_ORDINAL = 1454;
+
+    // FIELD: Number of requests made to an autofill service during a session.
+    // OS: P
+    FIELD_AUTOFILL_NUMBER_REQUESTS = 1455;
+
     // ---- End P Constants, all P constants go above this line ----
 
     // First Q constant in master goes here:
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index f781013..ad884c6 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -121,8 +121,11 @@
     @NonNull
     public static LogMaker newLogMaker(int category, String packageName,
             String servicePackageName, boolean compatMode) {
-        return newLogMaker(category, packageName, servicePackageName)
-                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE, compatMode ? 1 : 0);
+        final LogMaker log = newLogMaker(category, packageName, servicePackageName);
+        if (compatMode) {
+            log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE, 1);
+        }
+        return log;
     }
 
     public static void printlnRedactedText(@NonNull PrintWriter pw, @Nullable CharSequence text) {
@@ -193,6 +196,18 @@
         return urlBarNode;
     }
 
+    /**
+     * Gets the value of a metric tag, or {@code 0} if not found or NaN.
+     */
+    static int getNumericValue(@NonNull LogMaker log, int tag) {
+        final Object value = log.getTaggedData(tag);
+        if (!(value instanceof Number)) {
+            return 0;
+        } else {
+            return ((Number) value).intValue();
+        }
+    }
+
     private interface ViewNodeFilter {
         boolean matches(ViewNode node);
     }
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index 4ded3fe..3e932e8 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -99,12 +99,14 @@
     private PendingRequest mPendingRequest;
 
     public interface FillServiceCallbacks {
-        void onFillRequestSuccess(int requestFlags, @Nullable FillResponse response,
+        void onFillRequestSuccess(int requestId, @Nullable FillResponse response,
+                @NonNull String servicePackageName, int requestFlags);
+        void onFillRequestFailure(int requestId, @Nullable CharSequence message,
                 @NonNull String servicePackageName);
-        void onFillRequestFailure(@Nullable CharSequence message,
-                @NonNull String servicePackageName);
+        void onFillRequestTimeout(int requestId, @NonNull String servicePackageName);
         void onSaveRequestSuccess(@NonNull String servicePackageName,
                 @Nullable IntentSender intentSender);
+        // TODO(b/80093094): add timeout here too?
         void onSaveRequestFailure(@Nullable CharSequence message,
                 @NonNull String servicePackageName);
         void onServiceDied(RemoteFillService service);
@@ -301,21 +303,31 @@
         mContext.unbindService(mServiceConnection);
     }
 
-    private void dispatchOnFillRequestSuccess(PendingRequest pendingRequest, int requestFlags,
-            FillResponse response) {
+    private void dispatchOnFillRequestSuccess(@NonNull PendingFillRequest pendingRequest,
+            @Nullable FillResponse response, int requestFlags) {
         mHandler.post(() -> {
             if (handleResponseCallbackCommon(pendingRequest)) {
-                mCallbacks.onFillRequestSuccess(requestFlags, response,
+                mCallbacks.onFillRequestSuccess(pendingRequest.mRequest.getId(), response,
+                        mComponentName.getPackageName(), requestFlags);
+            }
+        });
+    }
+
+    private void dispatchOnFillRequestFailure(@NonNull PendingFillRequest pendingRequest,
+            @Nullable CharSequence message) {
+        mHandler.post(() -> {
+            if (handleResponseCallbackCommon(pendingRequest)) {
+                mCallbacks.onFillRequestFailure(pendingRequest.mRequest.getId(), message,
                         mComponentName.getPackageName());
             }
         });
     }
 
-    private void dispatchOnFillRequestFailure(PendingRequest pendingRequest,
-            @Nullable CharSequence message) {
+    private void dispatchOnFillRequestTimeout(@NonNull PendingFillRequest pendingRequest) {
         mHandler.post(() -> {
             if (handleResponseCallbackCommon(pendingRequest)) {
-                mCallbacks.onFillRequestFailure(message, mComponentName.getPackageName());
+                mCallbacks.onFillRequestTimeout(pendingRequest.mRequest.getId(),
+                        mComponentName.getPackageName());
             }
         });
     }
@@ -538,18 +550,18 @@
                     final RemoteFillService remoteService = getService();
                     if (remoteService != null) {
                         remoteService.dispatchOnFillRequestSuccess(PendingFillRequest.this,
-                                request.getFlags(), response);
+                                response, request.getFlags());
                     }
                 }
 
                 @Override
-                public void onFailure(CharSequence message) {
+                public void onFailure(int requestId, CharSequence message) {
                     if (!finish()) return;
 
                     final RemoteFillService remoteService = getService();
                     if (remoteService != null) {
-                        remoteService.dispatchOnFillRequestFailure(
-                                PendingFillRequest.this, message);
+                        remoteService.dispatchOnFillRequestFailure(PendingFillRequest.this,
+                                message);
                     }
                 }
             };
@@ -566,7 +578,7 @@
             if (cancellation != null) {
                 remoteService.dispatchOnFillTimeout(cancellation);
             }
-            remoteService.dispatchOnFillRequestFailure(PendingFillRequest.this, null);
+            remoteService.dispatchOnFillRequestTimeout(PendingFillRequest.this);
         }
 
         @Override
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 4b67bb1..a6f4e58 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -27,6 +27,7 @@
 import static android.view.autofill.AutofillManager.ACTION_VIEW_EXITED;
 
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+import static com.android.server.autofill.Helper.getNumericValue;
 import static com.android.server.autofill.Helper.sDebug;
 import static com.android.server.autofill.Helper.sPartitionMaxCount;
 import static com.android.server.autofill.Helper.sVerbose;
@@ -93,6 +94,7 @@
 import com.android.server.autofill.ui.PendingUi;
 
 import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -176,7 +178,7 @@
 
     /**
      * Contexts read from the app; they will be updated (sanitized, change values for save) before
-     * sent to {@link AutofillService}. Ordered by the time they we read.
+     * sent to {@link AutofillService}. Ordered by the time they were read.
      */
     @GuardedBy("mLock")
     private ArrayList<FillContext> mContexts;
@@ -231,6 +233,12 @@
     private final LocalLog mWtfHistory;
 
     /**
+     * Map of {@link MetricsEvent#AUTOFILL_REQUEST} metrics, keyed by fill request id.
+     */
+    @GuardedBy("mLock")
+    private final SparseArray<LogMaker> mRequestLogs = new SparseArray<>(1);
+
+    /**
      * Receiver of assist data from the app's {@link Activity}.
      */
     private final IAssistDataReceiver mAssistReceiver = new IAssistDataReceiver.Stub() {
@@ -483,8 +491,18 @@
             requestId = sIdCounter.getAndIncrement();
         } while (requestId == INVALID_REQUEST_ID);
 
+        // Create a metrics log for the request
+        final int ordinal = mRequestLogs.size() + 1;
+        final LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_REQUEST)
+                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_REQUEST_ORDINAL, ordinal);
+        if (flags != 0) {
+            log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_FLAGS, flags);
+        }
+        mRequestLogs.put(requestId, log);
+
         if (sVerbose) {
-            Slog.v(TAG, "Requesting structure for requestId=" + requestId + ", flags=" + flags);
+            Slog.v(TAG, "Requesting structure for request #" + ordinal + " ,requestId="
+                    + requestId + ", flags=" + flags);
         }
 
         // If the focus changes very quickly before the first request is returned each focus change
@@ -537,7 +555,7 @@
         setClientLocked(client);
 
         mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_SESSION_STARTED)
-                .addTaggedData(MetricsEvent.FIELD_FLAGS, flags));
+                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_FLAGS, flags));
     }
 
     /**
@@ -604,21 +622,30 @@
 
     // FillServiceCallbacks
     @Override
-    public void onFillRequestSuccess(int requestFlags, @Nullable FillResponse response,
-            @NonNull String servicePackageName) {
+    public void onFillRequestSuccess(int requestId, @Nullable FillResponse response,
+            @NonNull String servicePackageName, int requestFlags) {
         final AutofillId[] fieldClassificationIds;
 
+        final LogMaker requestLog;
+
         synchronized (mLock) {
             if (mDestroyed) {
                 Slog.w(TAG, "Call to Session#onFillRequestSuccess() rejected - session: "
                         + id + " destroyed");
                 return;
             }
+
+            requestLog = mRequestLogs.get(requestId);
+            if (requestLog != null) {
+                requestLog.setType(MetricsEvent.TYPE_SUCCESS);
+            } else {
+                Slog.w(TAG, "onFillRequestSuccess(): no request log for id " + requestId);
+            }
             if (response == null) {
+                if (requestLog != null) {
+                    requestLog.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS, -1);
+                }
                 processNullResponseLocked(requestFlags);
-                mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_REQUEST, servicePackageName)
-                        .setType(MetricsEvent.TYPE_SUCCESS)
-                        .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS, -1));
                 return;
             }
 
@@ -659,38 +686,54 @@
             // Response is "empty" from an UI point of view, need to notify client.
             notifyUnavailableToClient(sessionFinishedState);
         }
+
+        if (requestLog != null) {
+            requestLog.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS,
+                            response.getDatasets() == null ? 0 : response.getDatasets().size());
+            if (fieldClassificationIds != null) {
+                requestLog.addTaggedData(
+                        MetricsEvent.FIELD_AUTOFILL_NUM_FIELD_CLASSIFICATION_IDS,
+                        fieldClassificationIds.length);
+            }
+        }
+
         synchronized (mLock) {
             processResponseLocked(response, null, requestFlags);
         }
-
-        final LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_REQUEST, servicePackageName)
-                .setType(MetricsEvent.TYPE_SUCCESS)
-                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS,
-                        response.getDatasets() == null ? 0 : response.getDatasets().size());
-        if (fieldClassificationIds != null) {
-            log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_FIELD_CLASSIFICATION_IDS,
-                    fieldClassificationIds.length);
-        }
-        mMetricsLogger.write(log);
     }
 
     // FillServiceCallbacks
     @Override
-    public void onFillRequestFailure(@Nullable CharSequence message,
+    public void onFillRequestFailure(int requestId, @Nullable CharSequence message,
             @NonNull String servicePackageName) {
+        onFillRequestFailureOrTimeout(requestId, false, message, servicePackageName);
+    }
+
+    // FillServiceCallbacks
+    @Override
+    public void onFillRequestTimeout(int requestId, @NonNull String servicePackageName) {
+        onFillRequestFailureOrTimeout(requestId, true, null, servicePackageName);
+    }
+
+    private void onFillRequestFailureOrTimeout(int requestId, boolean timedOut,
+            @Nullable CharSequence message, @NonNull String servicePackageName) {
         synchronized (mLock) {
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#onFillRequestFailure() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(TAG, "Call to Session#onFillRequestFailureOrTimeout(req=" + requestId
+                        + ") rejected - session: " + id + " destroyed");
                 return;
             }
             mService.resetLastResponse();
+            final LogMaker requestLog = mRequestLogs.get(requestId);
+            if (requestLog == null) {
+                Slog.w(TAG, "onFillRequestFailureOrTimeout(): no log for id " + requestId);
+            } else {
+                requestLog.setType(timedOut ? MetricsEvent.TYPE_CLOSE : MetricsEvent.TYPE_FAILURE);
+            }
         }
-        LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_REQUEST, servicePackageName)
-                .setType(MetricsEvent.TYPE_FAILURE);
-        mMetricsLogger.write(log);
-
-        getUiForShowing().showError(message, this);
+        if (message != null) {
+            getUiForShowing().showError(message, this);
+        }
         removeSelf();
     }
 
@@ -973,11 +1016,12 @@
                     + ", clientState=" + newClientState);
         }
         if (result instanceof FillResponse) {
-            writeLog(MetricsEvent.AUTOFILL_AUTHENTICATED);
+            logAuthenticationStatusLocked(requestId, MetricsEvent.AUTOFILL_AUTHENTICATED);
             replaceResponseLocked(authenticatedResponse, (FillResponse) result, newClientState);
         } else if (result instanceof Dataset) {
             if (datasetIdx != AutofillManager.AUTHENTICATION_ID_DATASET_ID_UNDEFINED) {
-                writeLog(MetricsEvent.AUTOFILL_DATASET_AUTHENTICATED);
+                logAuthenticationStatusLocked(requestId,
+                        MetricsEvent.AUTOFILL_DATASET_AUTHENTICATED);
                 if (newClientState != null) {
                     if (sDebug) Slog.d(TAG,  "Updating client state from auth dataset");
                     mClientState = newClientState;
@@ -986,13 +1030,15 @@
                 authenticatedResponse.getDatasets().set(datasetIdx, dataset);
                 autoFill(requestId, datasetIdx, dataset, false);
             } else {
-                writeLog(MetricsEvent.AUTOFILL_INVALID_DATASET_AUTHENTICATION);
+                logAuthenticationStatusLocked(requestId,
+                        MetricsEvent.AUTOFILL_INVALID_DATASET_AUTHENTICATION);
             }
         } else {
             if (result != null) {
                 Slog.w(TAG, "service returned invalid auth type: " + result);
             }
-            writeLog(MetricsEvent.AUTOFILL_INVALID_AUTHENTICATION);
+            logAuthenticationStatusLocked(requestId,
+                    MetricsEvent.AUTOFILL_INVALID_AUTHENTICATION);
             processNullResponseLocked(0);
         }
     }
@@ -1404,7 +1450,7 @@
          *   the current values of all fields in the screen.
          */
         if (saveInfo == null) {
-            if (sVerbose) Slog.w(TAG, "showSaveLocked(): no saveInfo from service");
+            if (sVerbose) Slog.v(TAG, "showSaveLocked(): no saveInfo from service");
             return true;
         }
 
@@ -2065,7 +2111,7 @@
     }
 
     @Override
-    public void onFillReady(FillResponse response, AutofillId filledId,
+    public void onFillReady(@NonNull FillResponse response, @NonNull AutofillId filledId,
             @Nullable AutofillValue value) {
         synchronized (mLock) {
             if (mDestroyed) {
@@ -2103,9 +2149,8 @@
                 TimeUtils.formatDuration(duration, historyLog);
                 mUiLatencyHistory.log(historyLog.toString());
 
-                final LogMaker metricsLog = newLogMaker(MetricsEvent.AUTOFILL_UI_LATENCY)
-                        .addTaggedData(MetricsEvent.FIELD_AUTOFILL_DURATION, duration);
-                mMetricsLogger.write(metricsLog);
+                addTaggedDataToRequestLogLocked(response.getRequestId(),
+                        MetricsEvent.FIELD_AUTOFILL_DURATION, duration);
             }
         }
     }
@@ -2474,6 +2519,14 @@
             TimeUtils.formatDuration(mUiShownTime - mStartTime, pw);
             pw.println();
         }
+        final int requestLogsSizes = mRequestLogs.size();
+        pw.print(prefix); pw.print("mSessionLogs: "); pw.println(requestLogsSizes);
+        for (int i = 0; i < requestLogsSizes; i++) {
+            final int requestId = mRequestLogs.keyAt(i);
+            final LogMaker log = mRequestLogs.valueAt(i);
+            pw.print(prefix2); pw.print('#'); pw.print(i); pw.print(": req=");
+            pw.print(requestId); pw.print(", log=" ); dumpRequestLog(pw, log); pw.println();
+        }
         pw.print(prefix); pw.print("mResponses: ");
         if (mResponses == null) {
             pw.println("null");
@@ -2532,6 +2585,56 @@
         mRemoteFillService.dump(prefix, pw);
     }
 
+    private static void dumpRequestLog(@NonNull PrintWriter pw, @NonNull LogMaker log) {
+        pw.print("CAT="); pw.print(log.getCategory());
+        pw.print(", TYPE=");
+        final int type = log.getType();
+        switch (type) {
+            case MetricsEvent.TYPE_SUCCESS: pw.print("SUCCESS"); break;
+            case MetricsEvent.TYPE_FAILURE: pw.print("FAILURE"); break;
+            case MetricsEvent.TYPE_CLOSE: pw.print("CLOSE"); break;
+            default: pw.print("UNSUPPORTED");
+        }
+        pw.print('('); pw.print(type); pw.print(')');
+        pw.print(", PKG="); pw.print(log.getPackageName());
+        pw.print(", SERVICE="); pw.print(log
+                .getTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE));
+        pw.print(", ORDINAL="); pw.print(log
+                .getTaggedData(MetricsEvent.FIELD_AUTOFILL_REQUEST_ORDINAL));
+        dumpNumericValue(pw, log, "FLAGS", MetricsEvent.FIELD_AUTOFILL_FLAGS);
+        dumpNumericValue(pw, log, "NUM_DATASETS", MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS);
+        dumpNumericValue(pw, log, "UI_LATENCY", MetricsEvent.FIELD_AUTOFILL_DURATION);
+        final int authStatus =
+                getNumericValue(log, MetricsEvent.FIELD_AUTOFILL_AUTHENTICATION_STATUS);
+        if (authStatus != 0) {
+            pw.print(", AUTH_STATUS=");
+            switch (authStatus) {
+                case MetricsEvent.AUTOFILL_AUTHENTICATED:
+                    pw.print("AUTHENTICATED"); break;
+                case MetricsEvent.AUTOFILL_DATASET_AUTHENTICATED:
+                    pw.print("DATASET_AUTHENTICATED"); break;
+                case MetricsEvent.AUTOFILL_INVALID_AUTHENTICATION:
+                    pw.print("INVALID_AUTHENTICATION"); break;
+                case MetricsEvent.AUTOFILL_INVALID_DATASET_AUTHENTICATION:
+                    pw.print("INVALID_DATASET_AUTHENTICATION"); break;
+                default: pw.print("UNSUPPORTED");
+            }
+            pw.print('('); pw.print(authStatus); pw.print(')');
+        }
+        dumpNumericValue(pw, log, "FC_IDS",
+                MetricsEvent.FIELD_AUTOFILL_NUM_FIELD_CLASSIFICATION_IDS);
+        dumpNumericValue(pw, log, "COMPAT_MODE",
+                MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE);
+    }
+
+    private static void dumpNumericValue(@NonNull PrintWriter pw, @NonNull LogMaker log,
+            @NonNull String field, int tag) {
+        final int value = getNumericValue(log, tag);
+        if (value != 0) {
+            pw.print(", "); pw.print(field); pw.print('='); pw.print(value);
+        }
+    }
+
     void autoFillApp(Dataset dataset) {
         synchronized (mLock) {
             if (mDestroyed) {
@@ -2610,7 +2713,19 @@
         mUi.destroyAll(mPendingSaveUi, this, true);
         mUi.clearCallback(this);
         mDestroyed = true;
-        writeLog(MetricsEvent.AUTOFILL_SESSION_FINISHED);
+
+        // Log metrics
+        final int totalRequests = mRequestLogs.size();
+        if (totalRequests > 0) {
+            if (sVerbose) Slog.v(TAG, "destroyLocked(): logging " + totalRequests + " requests");
+            for (int i = 0; i < totalRequests; i++) {
+                final LogMaker log = mRequestLogs.valueAt(i);
+                mMetricsLogger.write(log);
+            }
+        }
+        mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_SESSION_FINISHED)
+                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUMBER_REQUESTS, totalRequests));
+
         return mRemoteFillService;
     }
 
@@ -2727,6 +2842,29 @@
         mMetricsLogger.write(newLogMaker(category));
     }
 
+    private void logAuthenticationStatusLocked(int requestId, int status) {
+        addTaggedDataToRequestLogLocked(requestId,
+                MetricsEvent.FIELD_AUTOFILL_AUTHENTICATION_STATUS, status);
+    }
+
+    private void addTaggedDataToRequestLogLocked(int requestId, int tag, @Nullable Object value) {
+        final LogMaker requestLog = mRequestLogs.get(requestId);
+        if (requestLog == null) {
+            Slog.w(TAG,
+                    "addTaggedDataToRequestLogLocked(tag=" + tag + "): no log for id " + requestId);
+            return;
+        }
+        requestLog.addTaggedData(tag, value);
+    }
+
+    private static String requestLogToString(@NonNull LogMaker log) {
+        final StringWriter sw = new StringWriter();
+        final PrintWriter pw = new PrintWriter(sw);
+        dumpRequestLog(pw, log);
+        pw.flush();
+        return sw.toString();
+    }
+
     private void wtf(@Nullable Exception e, String fmt, Object...args) {
         final String message = String.format(fmt, args);
         mWtfHistory.log(message);
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index cff1a84..bb97e4a 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -19,6 +19,7 @@
 import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
 import static com.android.server.autofill.Helper.sDebug;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.graphics.Rect;
 import android.service.autofill.FillResponse;
@@ -40,7 +41,7 @@
         /**
          * Called when the fill UI is ready to be shown for this view.
          */
-        void onFillReady(FillResponse fillResponse, AutofillId focusedId,
+        void onFillReady(@NonNull FillResponse fillResponse, @NonNull AutofillId focusedId,
                 @Nullable AutofillValue value);
     }