Improved autofill logging and dumping.

Bug: 76027553
Test: adb shell dumpsys autofill

Change-Id: I19ef88c71334c62292ed982e43d7a7e89b35f10e
diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java
index f32dee1..ccec483 100644
--- a/core/java/android/service/autofill/Dataset.java
+++ b/core/java/android/service/autofill/Dataset.java
@@ -149,24 +149,33 @@
     public String toString() {
         if (!sDebug) return super.toString();
 
-        final StringBuilder builder = new StringBuilder("Dataset[id=");
+        final StringBuilder builder = new StringBuilder("Dataset[");
         if (mId == null) {
-            builder.append("null");
+            builder.append("noId");
         } else {
             // Cannot disclose id because it could contain PII.
-            builder.append(mId.length()).append("_chars");
+            builder.append("id=").append(mId.length()).append("_chars");
         }
+        if (mFieldIds != null) {
+            builder.append(", fieldIds=").append(mFieldIds);
+        }
+        if (mFieldValues != null) {
+            builder.append(", fieldValues=").append(mFieldValues);
+        }
+        if (mFieldPresentations != null) {
+            builder.append(", fieldPresentations=").append(mFieldPresentations.size());
 
-        return builder
-                .append(", fieldIds=").append(mFieldIds)
-                .append(", fieldValues=").append(mFieldValues)
-                .append(", fieldPresentations=")
-                .append(mFieldPresentations == null ? 0 : mFieldPresentations.size())
-                .append(", fieldFilters=")
-                .append(mFieldFilters == null ? 0 : mFieldFilters.size())
-                .append(", hasPresentation=").append(mPresentation != null)
-                .append(", hasAuthentication=").append(mAuthentication != null)
-                .append(']').toString();
+        }
+        if (mFieldFilters != null) {
+            builder.append(", fieldFilters=").append(mFieldFilters.size());
+        }
+        if (mPresentation != null) {
+            builder.append(", hasPresentation");
+        }
+        if (mAuthentication != null) {
+            builder.append(", hasAuthentication");
+        }
+        return builder.append(']').toString();
     }
 
     /**
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index 3a4b6bb..25239b6 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -554,23 +554,40 @@
         if (!sDebug) return super.toString();
 
         // TODO: create a dump() method instead
-        return new StringBuilder(
-                "FillResponse : [mRequestId=" + mRequestId)
-                .append(", datasets=").append(mDatasets == null ? "N/A" : mDatasets.getList())
-                .append(", saveInfo=").append(mSaveInfo)
-                .append(", clientState=").append(mClientState != null)
-                .append(", hasPresentation=").append(mPresentation != null)
-                .append(", hasHeader=").append(mHeader != null)
-                .append(", hasFooter=").append(mFooter != null)
-                .append(", hasAuthentication=").append(mAuthentication != null)
-                .append(", authenticationIds=").append(Arrays.toString(mAuthenticationIds))
-                .append(", ignoredIds=").append(Arrays.toString(mIgnoredIds))
-                .append(", disableDuration=").append(mDisableDuration)
-                .append(", flags=").append(mFlags)
-                .append(", fieldClassificationIds=")
-                    .append(Arrays.toString(mFieldClassificationIds))
-                .append("]")
-                .toString();
+        final StringBuilder builder = new StringBuilder(
+                "FillResponse : [mRequestId=" + mRequestId);
+        if (mDatasets != null) {
+            builder.append(", datasets=").append(mDatasets.getList());
+        }
+        if (mSaveInfo != null) {
+            builder.append(", saveInfo=").append(mSaveInfo);
+        }
+        if (mClientState != null) {
+            builder.append(", hasClientState");
+        }
+        if (mPresentation != null) {
+            builder.append(", hasPresentation");
+        }
+        if (mHeader != null) {
+            builder.append(", hasHeader");
+        }
+        if (mFooter != null) {
+            builder.append(", hasFooter");
+        }
+        if (mAuthentication != null) {
+            builder.append(", hasAuthentication");
+        }
+        if (mAuthenticationIds != null) {
+            builder.append(", authenticationIds=").append(Arrays.toString(mAuthenticationIds));
+        }
+        builder.append(", disableDuration=").append(mDisableDuration);
+        if (mFlags != 0) {
+            builder.append(", flags=").append(mFlags);
+        }
+        if (mFieldClassificationIds != null) {
+            builder.append(Arrays.toString(mFieldClassificationIds));
+        }
+        return builder.append("]").toString();
     }
 
     /////////////////////////////////////
diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java
index a5a6177..d3067a9 100644
--- a/core/java/android/service/autofill/SaveInfo.java
+++ b/core/java/android/service/autofill/SaveInfo.java
@@ -699,22 +699,37 @@
     public String toString() {
         if (!sDebug) return super.toString();
 
-        return new StringBuilder("SaveInfo: [type=")
+        final StringBuilder builder = new StringBuilder("SaveInfo: [type=")
                 .append(DebugUtils.flagsToString(SaveInfo.class, "SAVE_DATA_TYPE_", mType))
                 .append(", requiredIds=").append(Arrays.toString(mRequiredIds))
-                .append(", optionalIds=").append(Arrays.toString(mOptionalIds))
-                .append(", description=").append(mDescription)
-                .append(DebugUtils.flagsToString(SaveInfo.class, "NEGATIVE_BUTTON_STYLE_",
-                        mNegativeButtonStyle))
-                .append(", flags=").append(mFlags)
-                .append(", customDescription=").append(mCustomDescription)
-                .append(", validator=").append(mValidator)
-                .append(", sanitizerKeys=")
-                    .append(mSanitizerKeys == null ? "N/A:" : mSanitizerKeys.length)
-                .append(", sanitizerValues=")
-                    .append(mSanitizerValues == null ? "N/A:" : mSanitizerValues.length)
-                .append(", triggerId=").append(mTriggerId)
-                .append("]").toString();
+                .append(", style=").append(DebugUtils.flagsToString(SaveInfo.class,
+                        "NEGATIVE_BUTTON_STYLE_", mNegativeButtonStyle));
+        if (mOptionalIds != null) {
+            builder.append(", optionalIds=").append(Arrays.toString(mOptionalIds));
+        }
+        if (mDescription != null) {
+            builder.append(", description=").append(mDescription);
+        }
+        if (mFlags != 0) {
+            builder.append(", flags=").append(mFlags);
+        }
+        if (mCustomDescription != null) {
+            builder.append(", customDescription=").append(mCustomDescription);
+        }
+        if (mValidator != null) {
+            builder.append(", validator=").append(mValidator);
+        }
+        if (mSanitizerKeys != null) {
+            builder.append(", sanitizerKeys=").append(mSanitizerKeys.length);
+        }
+        if (mSanitizerValues != null) {
+            builder.append(", sanitizerValues=").append(mSanitizerValues.length);
+        }
+        if (mTriggerId != null) {
+            builder.append(", triggerId=").append(mTriggerId);
+        }
+
+        return builder.append("]").toString();
     }
 
     /////////////////////////////////////
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 69938cb..abc19d0 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -2882,9 +2882,8 @@
         /**
          * @hide
          */
-        public String toString(String prefix) {
-            StringBuilder sb = new StringBuilder(256);
-            sb.append("{(");
+        public void dumpDimensions(StringBuilder sb) {
+            sb.append('(');
             sb.append(x);
             sb.append(',');
             sb.append(y);
@@ -2895,6 +2894,15 @@
             sb.append((height == MATCH_PARENT ? "fill" : (height == WRAP_CONTENT
                     ? "wrap" : String.valueOf(height))));
             sb.append(")");
+        }
+
+        /**
+         * @hide
+         */
+        public String toString(String prefix) {
+            StringBuilder sb = new StringBuilder(256);
+            sb.append('{');
+            dumpDimensions(sb);
             if (horizontalMargin != 0) {
                 sb.append(" hm=");
                 sb.append(horizontalMargin);
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 7409ec2..4d66674 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -80,6 +80,7 @@
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.autofill.AutofillManagerService.PackageCompatState;
 import com.android.server.autofill.ui.AutoFillUI;
 
 import java.io.FileDescriptor;
@@ -655,7 +656,7 @@
     /**
      * Compatibility mode metadata per package.
      */
-    private static final class PackageCompatState {
+    static final class PackageCompatState {
         private final long maxVersionCode;
         private final String[] urlBarResourceIds;
 
@@ -666,8 +667,8 @@
 
         @Override
         public String toString() {
-            return "PackageCompatState: [maxVersionCode=" + maxVersionCode
-                    + ", urlBarResourceIds=" + Arrays.toString(urlBarResourceIds) + "]";
+            return "maxVersionCode=" + maxVersionCode
+                    + ", urlBarResourceIds=" + Arrays.toString(urlBarResourceIds);
         }
     }
 
@@ -756,6 +757,25 @@
                 }
             }
         }
+
+        private void dump(String prefix, PrintWriter pw) {
+             if (mUserSpecs == null) {
+                 pw.println("N/A");
+                 return;
+             }
+             pw.println();
+             final String prefix2 = prefix + "  ";
+             for (int i = 0; i < mUserSpecs.size(); i++) {
+                 final int user = mUserSpecs.keyAt(i);
+                 pw.print(prefix); pw.print("User: "); pw.println(user);
+                 final ArrayMap<String,PackageCompatState> perUser = mUserSpecs.get(i);
+                 for (int j = 0; j < perUser.size(); j++) {
+                     final String packageName = perUser.keyAt(j);
+                     final PackageCompatState state = perUser.valueAt(j);
+                     pw.print(prefix2); pw.print(packageName); pw.print(": "); pw.println(state);
+                }
+            }
+        }
     }
 
     final class AutoFillManagerServiceStub extends IAutoFillManager.Stub {
@@ -1121,6 +1141,7 @@
 
             boolean oldDebug = sDebug;
             final String prefix = "  ";
+            final String prefix2 = "    ";
             try {
                 synchronized (mLock) {
                     oldDebug = sDebug;
@@ -1145,8 +1166,8 @@
                     }
                     mUi.dump(pw);
                     pw.print("Autofill Compat State: ");
-                    pw.println(mAutofillCompatState.mUserSpecs);
-                    pw.print(prefix); pw.print("from settings: ");
+                    mAutofillCompatState.dump(prefix2, pw);
+                    pw.print(prefix2); pw.print("from settings: ");
                     pw.println(getWhitelistedCompatModePackagesFromSettings());
                 }
                 if (showHistory) {
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index 5c41f3f..7bb532e 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -26,6 +26,7 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
+import android.view.WindowManager;
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillValue;
 
@@ -107,6 +108,13 @@
     }
 
     @NonNull
+    public static String paramsToString(@NonNull WindowManager.LayoutParams params) {
+        final StringBuilder builder = new StringBuilder(25);
+        params.dumpDimensions(builder);
+        return builder.toString();
+    }
+
+    @NonNull
     static ArrayMap<AutofillId, AutofillValue> getFields(@NonNull Dataset dataset) {
         final ArrayList<AutofillId> ids = dataset.getFieldIds();
         final ArrayList<AutofillValue> values = dataset.getFieldValues();
@@ -128,7 +136,7 @@
         return log;
     }
 
-    public static void printlnRedactedText(@NonNull PrintWriter pw, @Nullable String text) {
+    public static void printlnRedactedText(@NonNull PrintWriter pw, @Nullable CharSequence text) {
         if (text == null) {
             pw.println("null");
         } else {
@@ -173,6 +181,7 @@
      * @param structure Assist structure
      * @param urlBarIds list of ids; only the first id found will be sanitized.
      */
+    @Nullable
     public static void sanitizeUrlBar(@NonNull AssistStructure structure,
             @NonNull String[] urlBarIds) {
         final ViewNode urlBarNode = findViewNode(structure, (node) -> {
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index 0dbdc13..03c5850 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -206,29 +206,51 @@
 
     @Override
     public String toString() {
-        return "ViewState: [id=" + id + ", datasetId=" + mDatasetId
-                + ", currentValue=" + mCurrentValue
-                + ", autofilledValue=" + mAutofilledValue
-                + ", bounds=" + mVirtualBounds + ", state=" + getStateAsString() + "]";
+        final StringBuilder builder = new StringBuilder("ViewState: [id=").append(id);
+        if (mDatasetId != null) {
+            builder.append("datasetId:" ).append(mDatasetId);
+        }
+        builder.append("state:" ).append(getStateAsString());
+        if (mCurrentValue != null) {
+            builder.append("currentValue:" ).append(mCurrentValue);
+        }
+        if (mAutofilledValue != null) {
+            builder.append("autofilledValue:" ).append(mAutofilledValue);
+        }
+        if (mSanitizedValue != null) {
+            builder.append("sanitizedValue:" ).append(mSanitizedValue);
+        }
+        if (mVirtualBounds != null) {
+            builder.append("virtualBounds:" ).append(mVirtualBounds);
+        }
+        return builder.toString();
     }
 
     void dump(String prefix, PrintWriter pw) {
-        pw.print(prefix); pw.print("id:" ); pw.println(this.id);
-        pw.print(prefix); pw.print("datasetId:" ); pw.println(this.mDatasetId);
+        pw.print(prefix); pw.print("id:" ); pw.println(id);
+        if (mDatasetId != null) {
+            pw.print(prefix); pw.print("datasetId:" ); pw.println(mDatasetId);
+        }
         pw.print(prefix); pw.print("state:" ); pw.println(getStateAsString());
-        pw.print(prefix); pw.print("response:");
-        if (mResponse == null) {
-            pw.println("N/A");
-        } else {
+        if (mResponse != null) {
+            pw.print(prefix); pw.print("response:");
             if (sVerbose) {
                 pw.println(mResponse);
             } else {
-                pw.println(mResponse.getRequestId());
+                pw.print("id=");pw.println(mResponse.getRequestId());
             }
         }
-        pw.print(prefix); pw.print("currentValue:" ); pw.println(mCurrentValue);
-        pw.print(prefix); pw.print("autofilledValue:" ); pw.println(mAutofilledValue);
-        pw.print(prefix); pw.print("sanitizedValue:" ); pw.println(mSanitizedValue);
-        pw.print(prefix); pw.print("virtualBounds:" ); pw.println(mVirtualBounds);
+        if (mCurrentValue != null) {
+            pw.print(prefix); pw.print("currentValue:" ); pw.println(mCurrentValue);
+        }
+        if (mAutofilledValue != null) {
+            pw.print(prefix); pw.print("autofilledValue:" ); pw.println(mAutofilledValue);
+        }
+        if (mSanitizedValue != null) {
+            pw.print(prefix); pw.print("sanitizedValue:" ); pw.println(mSanitizedValue);
+        }
+        if (mVirtualBounds != null) {
+            pw.print(prefix); pw.print("virtualBounds:" ); pw.println(mVirtualBounds);
+        }
     }
 }
\ No newline at end of file
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index ef4656b..edfc412 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -15,6 +15,7 @@
  */
 package com.android.server.autofill.ui;
 
+import static com.android.server.autofill.Helper.paramsToString;
 import static com.android.server.autofill.Helper.sDebug;
 import static com.android.server.autofill.Helper.sVerbose;
 
@@ -37,7 +38,6 @@
 import android.util.TypedValue;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
-import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.MeasureSpec;
 import android.view.ViewGroup;
@@ -568,12 +568,24 @@
 
         @Override
         public String toString() {
-            return "ViewItem: [dataset=" + (dataset == null ? "null" : dataset.getId())
-                    + ", value=" + (value == null ? "null" : value.length() + "_chars")
-                    + ", filterable=" + filterable
-                    + ", filter=" + (filter == null ? "null" : filter.pattern().length() + "_chars")
-                    + ", view=" + view.getAutofillId()
-                    + "]";
+            final StringBuilder builder = new StringBuilder("ViewItem:[view=")
+                    .append(view.getAutofillId());
+            final String datasetId = dataset == null ? null : dataset.getId();
+            if (datasetId != null) {
+                builder.append(", dataset=").append(datasetId);
+            }
+            if (value != null) {
+                // Cannot print value because it could contain PII
+                builder.append(", value=").append(value.length()).append("_chars");
+            }
+            if (filterable) {
+                builder.append(", filterable");
+            }
+            if (filter != null) {
+                // Filter should not have PII, but it could be a huge regexp
+                builder.append(", filter=").append(filter.pattern().length()).append("_chars");
+            }
+            return builder.append(']').toString();
         }
     }
 
@@ -583,8 +595,7 @@
                 boolean fitsSystemWindows, int layoutDirection) {
             if (sVerbose) {
                 Slog.v(TAG, "AutofillWindowPresenter.show(): fit=" + fitsSystemWindows
-                        + ", epicenter="+ transitionEpicenter + ", dir=" + layoutDirection
-                        + ", params=" + p);
+                        + ", params=" + paramsToString(p));
             }
             UiThread.getHandler().post(() -> mWindow.show(p));
         }
@@ -616,7 +627,9 @@
          * Shows the window.
          */
         public void show(WindowManager.LayoutParams params) {
-            if (sVerbose) Slog.v(TAG, "show(): showing=" + mShowing + ", params="+  params);
+            if (sVerbose) {
+                Slog.v(TAG, "show(): showing=" + mShowing + ", params=" + paramsToString(params));
+            }
             try {
                 // Okay here is a bit of voodoo - we want to show the window as system
                 // controlled one so it covers app windows - adjust the params accordingly.