Merge "Autofill metrics improvements:"
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index ba6bb23..935b787 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3953,6 +3953,10 @@
 
     // An autofill session was started
     // 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
     AUTOFILL_SESSION_STARTED = 906;
 
     // An autofill request was processed by a service
@@ -3960,7 +3964,11 @@
     // Type TYPE_FAILURE: The request failed
     // Package: Package of app that is autofilled
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
-    // Tag FIELD_AUTOFILL_NUM_DATASET: The number of datasets returned (only in success case)
+    // Tag FIELD_AUTOFILL_NUM_DATASETS: The number of datasets returned (only in success case)
+    // NOTE: starting on OS P, it also added:
+    // Type TYPE_CLOSE: Service returned a null response.
+    // Tag FIELD_AUTOFILL_NUM_FIELD_CLASSIFICATION_IDS: if service requested field classification,
+    // number of entries field ids in the request.
     AUTOFILL_REQUEST = 907;
 
     // Tag of a field for a package of an autofill service
@@ -4863,7 +4871,6 @@
     // Counter: duration (in ms) that autofill will be disabled
     // OS: P
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
-    // Tag FIELD_CLASS_NAME: Name of the Package of service that processed the request
     AUTOFILL_SERVICE_DISABLED_APP = 1231;
 
     // An autofill service asked to disable autofill for a given activity.
@@ -5067,6 +5074,26 @@
     // OS: P
     NOTIFICATION_ZEN_MODE_RULE_SELECTION_DIALOG = 1270;
 
+    // Tag of a field for the number of ids in an autofill field classification request.
+    FIELD_AUTOFILL_NUM_FIELD_CLASSIFICATION_IDS = 1271;
+
+    // An autofill service updated its user data
+    // Package: Package of the autofill service that updated the user data
+    // Counter: number of fields added (or 0 if reset)
+    // OS: P
+    AUTOFILL_USERDATA_UPDATED = 1272;
+
+    // Some data entered by the user matched the field classification requested by the service.
+    // Package: Package of app that is autofilled
+    // Counter: number of matches found
+    // 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
+    AUTOFILL_FIELD_CLASSIFICATION_MATCHES = 1273;
+
+    // Tag used to report autofill field classification scores
+    FIELD_AUTOFILL_MATCH_SCORE = 1274;
+
     // ---- End P Constants, all P constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index b2a0ce5..7bc63f0 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -36,6 +36,7 @@
 import android.content.pm.ServiceInfo;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.metrics.LogMaker;
 import android.os.AsyncTask;
 import android.os.Binder;
 import android.os.Bundle;
@@ -352,7 +353,7 @@
         pruneAbandonedSessionsLocked();
 
         final Session newSession = createSessionByTokenLocked(activityToken, uid, appCallbackToken,
-                hasCallback, componentName);
+                hasCallback, componentName, flags);
         if (newSession == null) {
             return NO_SESSION;
         }
@@ -453,7 +454,7 @@
 
     private Session createSessionByTokenLocked(@NonNull IBinder activityToken, int uid,
             @NonNull IBinder appCallbackToken, boolean hasCallback,
-            @NonNull ComponentName componentName) {
+            @NonNull ComponentName componentName, int flags) {
         // use random ids so that one app cannot know that another app creates sessions
         int sessionId;
         int tries = 0;
@@ -471,7 +472,7 @@
 
         final Session newSession = new Session(this, mUi, mContext, mHandlerCaller, mUserId, mLock,
                 sessionId, uid, activityToken, appCallbackToken, hasCallback,
-                mUiLatencyHistory, mInfo.getServiceInfo().getComponentName(), componentName);
+                mUiLatencyHistory, mInfo.getServiceInfo().getComponentName(), componentName, flags);
         mSessions.put(newSession.id, newSession);
 
         return newSession;
@@ -716,7 +717,8 @@
             @Nullable ArrayList<AutofillId> manuallyFilledFieldIds,
             @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
             @Nullable ArrayList<AutofillId> detectedFieldIdsList,
-            @Nullable ArrayList<Match> detectedMatchesList) {
+            @Nullable ArrayList<Match> detectedMatchesList,
+            @NonNull String appPackageName) {
 
         synchronized (mLock) {
             if (isValidEventLocked("logDatasetNotSelected()", sessionId)) {
@@ -727,6 +729,19 @@
                     detectedFieldIdsList.toArray(detectedFieldsIds);
                     detectedMatches = new Match[detectedMatchesList.size()];
                     detectedMatchesList.toArray(detectedMatches);
+
+                    final int size = detectedMatchesList.size();
+                    float totalScore = 0;
+                    for (int i = 0; i < size; i++) {
+                        totalScore += detectedMatches[i].getScore();
+                    }
+                    final int averageScore = (int) ((totalScore * 100) / size);
+                    mMetricsLogger.write(
+                            Helper.newLogMaker(MetricsEvent.AUTOFILL_FIELD_CLASSIFICATION_MATCHES,
+                                    appPackageName, getServicePackageName())
+                            .setCounterValue(size)
+                            .addTaggedData(MetricsEvent.FIELD_AUTOFILL_MATCH_SCORE, averageScore));
+
                 }
                 mEventHistory.addEvent(new Event(Event.TYPE_CONTEXT_COMMITTED, null,
                         clientState, selectedDatasets, ignoredDatasets,
@@ -776,6 +791,11 @@
         synchronized (mLock) {
             if (isCalledByServiceLocked("setUserData", callingUid)) {
                 mUserData = userData;
+                // Log it
+                int numberFields = mUserData == null ? 0: mUserData.getRemoteIds().length;
+                mMetricsLogger.write(Helper.newLogMaker(MetricsEvent.AUTOFILL_USERDATA_UPDATED,
+                        getServicePackageName(), null)
+                        .setCounterValue(numberFields));
             }
         }
     }
@@ -1013,10 +1033,12 @@
                 expiration = Long.MAX_VALUE;
             }
             mDisabledActivities.put(componentName, expiration);
-            int intDuration = duration > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) duration;
-            mMetricsLogger.write(Helper.newLogMaker(MetricsEvent.AUTOFILL_SERVICE_DISABLED_ACTIVITY,
-                    componentName.getPackageName(), getServicePackageName())
-                    .addTaggedData(MetricsEvent.FIELD_CLASS_NAME, componentName.getClassName())
+            final int intDuration = duration > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) duration;
+            // NOTE: not using Helper.newLogMaker() because we're setting the componentName instead
+            // of package name
+            mMetricsLogger.write(new LogMaker(MetricsEvent.AUTOFILL_SERVICE_DISABLED_ACTIVITY)
+                    .setComponentName(componentName)
+                    .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, getServicePackageName())
                     .setCounterValue(intDuration));
         }
     }
@@ -1034,7 +1056,8 @@
                 if (expiration >= elapsedTime) return true;
                 // Restriction expired - clean it up.
                 if (sVerbose) {
-                    Slog.v(TAG, "Removing " + componentName.toShortString() + " from disabled list");
+                    Slog.v(TAG, "Removing " + componentName.toShortString()
+                        + " from disabled list");
                 }
                 mDisabledActivities.remove(componentName);
             }
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 4e64afb..56f5f64 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -128,6 +128,9 @@
     /** uid the session is for */
     public final int uid;
 
+    /** Flags used to start the session */
+    public final int mFlags;
+
     @GuardedBy("mLock")
     @NonNull private IBinder mActivityToken;
 
@@ -441,8 +444,10 @@
             @NonNull Context context, @NonNull HandlerCaller handlerCaller, int userId,
             @NonNull Object lock, int sessionId, int uid, @NonNull IBinder activityToken,
             @NonNull IBinder client, boolean hasCallback, @NonNull LocalLog uiLatencyHistory,
-            @NonNull ComponentName serviceComponentName, @NonNull ComponentName componentName) {
+            @NonNull ComponentName serviceComponentName, @NonNull ComponentName componentName,
+            int flags) {
         id = sessionId;
+        mFlags = flags;
         this.uid = uid;
         mStartTime = SystemClock.elapsedRealtime();
         mService = service;
@@ -456,7 +461,8 @@
         mComponentName = componentName;
         mClient = IAutoFillManagerClient.Stub.asInterface(client);
 
-        writeLog(MetricsEvent.AUTOFILL_SESSION_STARTED);
+        mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_SESSION_STARTED)
+                .addTaggedData(MetricsEvent.FIELD_FLAGS, flags));
     }
 
     /**
@@ -505,8 +511,9 @@
             }
         }
 
-        // TODO(b/67867469): remove once feature is finished
-        if (response.getFieldClassificationIds() != null && !mService.isFieldClassificationEnabled()) {
+        final AutofillId[] fieldClassificationIds = response.getFieldClassificationIds();
+        // TODO(b/67867469): remove once feature is finished (or use method from AFM to check)
+        if (fieldClassificationIds != null && !mService.isFieldClassificationEnabled()) {
             Slog.w(TAG, "Ignoring " + response + " because field detection is disabled");
             processNullResponseLocked(requestFlags);
             return;
@@ -548,6 +555,10 @@
                 .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);
     }
 
@@ -1106,7 +1117,7 @@
         mService.logContextCommitted(id, mClientState, mSelectedDatasetIds, ignoredDatasets,
                 changedFieldIds, changedDatasetIds,
                 manuallyFilledFieldIds, manuallyFilledDatasetIds,
-                detectedFieldIds, detectedMatches);
+                detectedFieldIds, detectedMatches, mComponentName.getPackageName());
     }
 
     /**
@@ -2115,6 +2126,7 @@
         final String prefix2 = prefix + "  ";
         pw.print(prefix); pw.print("id: "); pw.println(id);
         pw.print(prefix); pw.print("uid: "); pw.println(uid);
+        pw.print(prefix); pw.print("flags: "); pw.println(mFlags);
         pw.print(prefix); pw.print("mComponentName: "); pw.println(mComponentName);
         pw.print(prefix); pw.print("mActivityToken: "); pw.println(mActivityToken);
         pw.print(prefix); pw.print("mStartTime: "); pw.println(mStartTime);