Merge "Only have one way of dumping print manager state"
diff --git a/core/java/com/android/internal/print/DualDumpOutputStream.java b/core/java/com/android/internal/print/DualDumpOutputStream.java
new file mode 100644
index 0000000..f7826cc
--- /dev/null
+++ b/core/java/com/android/internal/print/DualDumpOutputStream.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2018 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.internal.print;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.ArrayMap;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.Preconditions;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+
+/**
+ * Dump either to a proto or a print writer using the same interface.
+ *
+ * <p>This mirrors the interface of {@link ProtoOutputStream}.
+ */
+public class DualDumpOutputStream {
+    // When writing to a proto, the proto
+    private final @Nullable ProtoOutputStream mProtoStream;
+
+    // When printing in clear text, the writer
+    private final @Nullable IndentingPrintWriter mIpw;
+    // Temporary storage of data when printing to mIpw
+    private final LinkedList<DumpObject> mDumpObjects = new LinkedList<>();
+
+    private static abstract class DumpAble {
+        final String name;
+
+        private DumpAble(String name) {
+            this.name = name;
+        }
+
+        abstract void print(IndentingPrintWriter ipw, boolean printName);
+    }
+
+    private static class DumpObject extends DumpAble {
+        private final LinkedHashMap<String, ArrayList<DumpAble>> mSubObjects = new LinkedHashMap<>();
+
+        private DumpObject(String name) {
+            super(name);
+        }
+
+        @Override
+        void print(IndentingPrintWriter ipw, boolean printName) {
+            if (printName) {
+                ipw.println(name + "={");
+            } else {
+                ipw.println("{");
+            }
+            ipw.increaseIndent();
+
+            for (ArrayList<DumpAble> subObject: mSubObjects.values()) {
+                int numDumpables = subObject.size();
+
+                if (numDumpables == 1) {
+                    subObject.get(0).print(ipw, true);
+                } else {
+                    ipw.println(subObject.get(0).name + "=[");
+                    ipw.increaseIndent();
+
+                    for (int i = 0; i < numDumpables; i++) {
+                        subObject.get(i).print(ipw, false);
+                    }
+
+                    ipw.decreaseIndent();
+                    ipw.println("]");
+                }
+            }
+
+            ipw.decreaseIndent();
+            ipw.println("}");
+        }
+
+        /**
+         * Add new field / subobject to this object.
+         *
+         * <p>If a name is added twice, they will be printed as a array
+         *
+         * @param fieldName name of the field added
+         * @param d The dumpable to add
+         */
+        public void add(String fieldName, DumpAble d) {
+            ArrayList<DumpAble> l = mSubObjects.get(fieldName);
+
+            if (l == null) {
+                l = new ArrayList<>(1);
+                mSubObjects.put(fieldName, l);
+            }
+
+            l.add(d);
+        }
+    }
+
+    private static class DumpField extends DumpAble {
+        private final String mValue;
+
+        private DumpField(String name, String value) {
+            super(name);
+            this.mValue = value;
+        }
+
+        @Override
+        void print(IndentingPrintWriter ipw, boolean printName) {
+            if (printName) {
+                ipw.println(name + "=" + mValue);
+            } else {
+                ipw.println(mValue);
+            }
+        }
+    }
+
+
+    /**
+     * Create a new DualDumpOutputStream. Only one output should be set.
+     *
+     * @param proto If dumping to proto the {@link ProtoOutputStream}
+     * @param ipw If dumping to a print writer, the {@link IndentingPrintWriter}
+     */
+    public DualDumpOutputStream(@Nullable ProtoOutputStream proto,
+            @Nullable IndentingPrintWriter ipw) {
+        Preconditions.checkArgument((proto == null) != (ipw == null));
+
+        mProtoStream = proto;
+        mIpw = ipw;
+
+        if (!isProto()) {
+            // Add root object
+            mDumpObjects.add(new DumpObject(null));
+        }
+    }
+
+    public void write(@NonNull String fieldName, long fieldId, double val) {
+        if (mProtoStream != null) {
+            mProtoStream.write(fieldId, val);
+        } else {
+            mDumpObjects.getLast().add(fieldName, new DumpField(fieldName, String.valueOf(val)));
+        }
+    }
+
+    public void write(@NonNull String fieldName, long fieldId, boolean val) {
+        if (mProtoStream != null) {
+            mProtoStream.write(fieldId, val);
+        } else {
+            mDumpObjects.getLast().add(fieldName, new DumpField(fieldName, String.valueOf(val)));
+        }
+    }
+
+    public void write(@NonNull String fieldName, long fieldId, int val) {
+        if (mProtoStream != null) {
+            mProtoStream.write(fieldId, val);
+        } else {
+            mDumpObjects.getLast().add(fieldName, new DumpField(fieldName, String.valueOf(val)));
+        }
+    }
+
+    public void write(@NonNull String fieldName, long fieldId, float val) {
+        if (mProtoStream != null) {
+            mProtoStream.write(fieldId, val);
+        } else {
+            mDumpObjects.getLast().add(fieldName, new DumpField(fieldName, String.valueOf(val)));
+        }
+    }
+
+    public void write(@NonNull String fieldName, long fieldId, byte[] val) {
+        if (mProtoStream != null) {
+            mProtoStream.write(fieldId, val);
+        } else {
+            mDumpObjects.getLast().add(fieldName, new DumpField(fieldName, Arrays.toString(val)));
+        }
+    }
+
+    public void write(@NonNull String fieldName, long fieldId, long val) {
+        if (mProtoStream != null) {
+            mProtoStream.write(fieldId, val);
+        } else {
+            mDumpObjects.getLast().add(fieldName, new DumpField(fieldName, String.valueOf(val)));
+        }
+    }
+
+    public void write(@NonNull String fieldName, long fieldId, @Nullable String val) {
+        if (mProtoStream != null) {
+            mProtoStream.write(fieldId, val);
+        } else {
+            mDumpObjects.getLast().add(fieldName, new DumpField(fieldName, String.valueOf(val)));
+        }
+    }
+
+    public long start(@NonNull String fieldName, long fieldId) {
+        if (mProtoStream != null) {
+            return mProtoStream.start(fieldId);
+        } else {
+            DumpObject d = new DumpObject(fieldName);
+            mDumpObjects.getLast().add(fieldName, d);
+            mDumpObjects.addLast(d);
+            return 0;
+        }
+    }
+
+    public void end(long token) {
+        if (mProtoStream != null) {
+            mProtoStream.end(token);
+        } else {
+            mDumpObjects.removeLast();
+        }
+    }
+
+    public void flush() {
+        if (mProtoStream != null) {
+            mProtoStream.flush();
+        } else {
+            if (mDumpObjects.size() == 1) {
+                mDumpObjects.getFirst().print(mIpw, false);
+
+                // Reset root object
+                mDumpObjects.clear();
+                mDumpObjects.add(new DumpObject(null));
+            }
+
+            mIpw.flush();
+        }
+    }
+
+    /**
+     * Add a dump from a different service into this dump.
+     *
+     * <p>Only for clear text dump. For proto dump use {@link #write(String, long, byte[])}.
+     *
+     * @param fieldName The name of the field
+     * @param nestedState The state of the dump
+     */
+    public void writeNested(@NonNull String fieldName, byte[] nestedState) {
+        Preconditions.checkNotNull(mIpw);
+
+        mDumpObjects.getLast().add(fieldName,
+                new DumpField(fieldName, (new String(nestedState, StandardCharsets.UTF_8)).trim()));
+    }
+
+    /**
+     * @return {@code true} iff we are dumping to a proto
+     */
+    public boolean isProto() {
+        return mProtoStream != null;
+    }
+}
diff --git a/core/java/com/android/internal/print/DumpUtils.java b/core/java/com/android/internal/print/DumpUtils.java
index 28c7fc2..3192d5c 100644
--- a/core/java/com/android/internal/print/DumpUtils.java
+++ b/core/java/com/android/internal/print/DumpUtils.java
@@ -39,7 +39,6 @@
 import android.service.print.PrinterIdProto;
 import android.service.print.PrinterInfoProto;
 import android.service.print.ResolutionProto;
-import android.util.proto.ProtoOutputStream;
 
 /**
  * Utilities for dumping print related proto buffer
@@ -49,13 +48,14 @@
      * Write a string to a proto if the string is not {@code null}.
      *
      * @param proto The proto to write to
+     * @param idName Clear text name of the proto-id
      * @param id The proto-id of the string
      * @param string The string to write
      */
-    public static void writeStringIfNotNull(@NonNull ProtoOutputStream proto, long id,
-            @Nullable String string) {
+    public static void writeStringIfNotNull(@NonNull DualDumpOutputStream proto, String idName,
+            long id, @Nullable String string) {
         if (string != null) {
-            proto.write(id, string);
+            proto.write(idName, id, string);
         }
     }
 
@@ -63,14 +63,15 @@
      * Write a {@link ComponentName} to a proto.
      *
      * @param proto The proto to write to
+     * @param idName Clear text name of the proto-id
      * @param id The proto-id of the component name
      * @param component The component name to write
      */
-    public static void writeComponentName(@NonNull ProtoOutputStream proto, long id,
-            @NonNull ComponentName component) {
-        long token = proto.start(id);
-        proto.write(ComponentNameProto.PACKAGE_NAME, component.getPackageName());
-        proto.write(ComponentNameProto.CLASS_NAME, component.getClassName());
+    public static void writeComponentName(@NonNull DualDumpOutputStream proto, String idName,
+            long id, @NonNull ComponentName component) {
+        long token = proto.start(idName, id);
+        proto.write("package_name", ComponentNameProto.PACKAGE_NAME, component.getPackageName());
+        proto.write("class_name", ComponentNameProto.CLASS_NAME, component.getClassName());
         proto.end(token);
     }
 
@@ -78,14 +79,16 @@
      * Write a {@link PrinterId} to a proto.
      *
      * @param proto The proto to write to
+     * @param idName Clear text name of the proto-id
      * @param id The proto-id of the component name
      * @param printerId The printer id to write
      */
-    public static void writePrinterId(@NonNull ProtoOutputStream proto, long id,
+    public static void writePrinterId(@NonNull DualDumpOutputStream proto, String idName, long id,
             @NonNull PrinterId printerId) {
-        long token = proto.start(id);
-        writeComponentName(proto, PrinterIdProto.SERVICE_NAME, printerId.getServiceName());
-        proto.write(PrinterIdProto.LOCAL_ID, printerId.getLocalId());
+        long token = proto.start(idName, id);
+        writeComponentName(proto, "service_name", PrinterIdProto.SERVICE_NAME,
+                printerId.getServiceName());
+        proto.write("local_id", PrinterIdProto.LOCAL_ID, printerId.getLocalId());
         proto.end(token);
     }
 
@@ -93,71 +96,76 @@
      * Write a {@link PrinterCapabilitiesInfo} to a proto.
      *
      * @param proto The proto to write to
+     * @param idName Clear text name of the proto-id
      * @param id The proto-id of the component name
      * @param cap The capabilities to write
      */
     public static void writePrinterCapabilities(@NonNull Context context,
-            @NonNull ProtoOutputStream proto, long id, @NonNull PrinterCapabilitiesInfo cap) {
-        long token = proto.start(id);
-        writeMargins(proto, PrinterCapabilitiesProto.MIN_MARGINS, cap.getMinMargins());
+            @NonNull DualDumpOutputStream proto, String idName, long id,
+            @NonNull PrinterCapabilitiesInfo cap) {
+        long token = proto.start(idName, id);
+        writeMargins(proto, "min_margins", PrinterCapabilitiesProto.MIN_MARGINS,
+                cap.getMinMargins());
 
         int numMediaSizes = cap.getMediaSizes().size();
         for (int i = 0; i < numMediaSizes; i++) {
-            writeMediaSize(context, proto, PrinterCapabilitiesProto.MEDIA_SIZES,
+            writeMediaSize(context, proto, "media_sizes", PrinterCapabilitiesProto.MEDIA_SIZES,
                     cap.getMediaSizes().get(i));
         }
 
         int numResolutions = cap.getResolutions().size();
         for (int i = 0; i < numResolutions; i++) {
-            writeResolution(proto, PrinterCapabilitiesProto.RESOLUTIONS,
+            writeResolution(proto, "resolutions", PrinterCapabilitiesProto.RESOLUTIONS,
                     cap.getResolutions().get(i));
         }
 
         if ((cap.getColorModes() & PrintAttributes.COLOR_MODE_MONOCHROME) != 0) {
-            proto.write(PrinterCapabilitiesProto.COLOR_MODES,
+            proto.write("color_modes", PrinterCapabilitiesProto.COLOR_MODES,
                     PrintAttributesProto.COLOR_MODE_MONOCHROME);
         }
         if ((cap.getColorModes() & PrintAttributes.COLOR_MODE_COLOR) != 0) {
-            proto.write(PrinterCapabilitiesProto.COLOR_MODES,
+            proto.write("color_modes", PrinterCapabilitiesProto.COLOR_MODES,
                     PrintAttributesProto.COLOR_MODE_COLOR);
         }
 
         if ((cap.getDuplexModes() & PrintAttributes.DUPLEX_MODE_NONE) != 0) {
-            proto.write(PrinterCapabilitiesProto.DUPLEX_MODES,
+            proto.write("duplex_modes", PrinterCapabilitiesProto.DUPLEX_MODES,
                     PrintAttributesProto.DUPLEX_MODE_NONE);
         }
         if ((cap.getDuplexModes() & PrintAttributes.DUPLEX_MODE_LONG_EDGE) != 0) {
-            proto.write(PrinterCapabilitiesProto.DUPLEX_MODES,
+            proto.write("duplex_modes", PrinterCapabilitiesProto.DUPLEX_MODES,
                     PrintAttributesProto.DUPLEX_MODE_LONG_EDGE);
         }
         if ((cap.getDuplexModes() & PrintAttributes.DUPLEX_MODE_SHORT_EDGE) != 0) {
-            proto.write(PrinterCapabilitiesProto.DUPLEX_MODES,
+            proto.write("duplex_modes", PrinterCapabilitiesProto.DUPLEX_MODES,
                     PrintAttributesProto.DUPLEX_MODE_SHORT_EDGE);
         }
 
         proto.end(token);
     }
 
-
     /**
      * Write a {@link PrinterInfo} to a proto.
      *
      * @param context The context used to resolve resources
      * @param proto The proto to write to
+     * @param idName Clear text name of the proto-id
      * @param id The proto-id of the component name
      * @param info The printer info to write
      */
-    public static void writePrinterInfo(@NonNull Context context, @NonNull ProtoOutputStream proto,
-            long id, @NonNull PrinterInfo info) {
-        long token = proto.start(id);
-        writePrinterId(proto, PrinterInfoProto.ID, info.getId());
-        proto.write(PrinterInfoProto.NAME, info.getName());
-        proto.write(PrinterInfoProto.STATUS, info.getStatus());
-        proto.write(PrinterInfoProto.DESCRIPTION, info.getDescription());
+    public static void writePrinterInfo(@NonNull Context context,
+            @NonNull DualDumpOutputStream proto, String idName, long id,
+            @NonNull PrinterInfo info) {
+        long token = proto.start(idName, id);
+        writePrinterId(proto, "id", PrinterInfoProto.ID, info.getId());
+        proto.write("name", PrinterInfoProto.NAME, info.getName());
+        proto.write("status", PrinterInfoProto.STATUS, info.getStatus());
+        proto.write("description", PrinterInfoProto.DESCRIPTION, info.getDescription());
 
         PrinterCapabilitiesInfo cap = info.getCapabilities();
         if (cap != null) {
-            writePrinterCapabilities(context, proto, PrinterInfoProto.CAPABILITIES, cap);
+            writePrinterCapabilities(context, proto, "capabilities", PrinterInfoProto.CAPABILITIES,
+                    cap);
         }
 
         proto.end(token);
@@ -168,16 +176,17 @@
      *
      * @param context The context used to resolve resources
      * @param proto The proto to write to
+     * @param idName Clear text name of the proto-id
      * @param id The proto-id of the component name
      * @param mediaSize The media size to write
      */
-    public static void writeMediaSize(@NonNull Context context, @NonNull ProtoOutputStream proto,
-            long id, @NonNull PrintAttributes.MediaSize mediaSize) {
-        long token = proto.start(id);
-        proto.write(MediaSizeProto.ID, mediaSize.getId());
-        proto.write(MediaSizeProto.LABEL, mediaSize.getLabel(context.getPackageManager()));
-        proto.write(MediaSizeProto.HEIGHT_MILS, mediaSize.getHeightMils());
-        proto.write(MediaSizeProto.WIDTH_MILS, mediaSize.getWidthMils());
+    public static void writeMediaSize(@NonNull Context context, @NonNull DualDumpOutputStream proto,
+            String idName, long id, @NonNull PrintAttributes.MediaSize mediaSize) {
+        long token = proto.start(idName, id);
+        proto.write("id", MediaSizeProto.ID, mediaSize.getId());
+        proto.write("label", MediaSizeProto.LABEL, mediaSize.getLabel(context.getPackageManager()));
+        proto.write("height_mils", MediaSizeProto.HEIGHT_MILS, mediaSize.getHeightMils());
+        proto.write("width_mils", MediaSizeProto.WIDTH_MILS, mediaSize.getWidthMils());
         proto.end(token);
     }
 
@@ -185,16 +194,17 @@
      * Write a {@link PrintAttributes.Resolution} to a proto.
      *
      * @param proto The proto to write to
+     * @param idName Clear text name of the proto-id
      * @param id The proto-id of the component name
      * @param res The resolution to write
      */
-    public static void writeResolution(@NonNull ProtoOutputStream proto, long id,
+    public static void writeResolution(@NonNull DualDumpOutputStream proto, String idName, long id,
             @NonNull PrintAttributes.Resolution res) {
-        long token = proto.start(id);
-        proto.write(ResolutionProto.ID, res.getId());
-        proto.write(ResolutionProto.LABEL, res.getLabel());
-        proto.write(ResolutionProto.HORIZONTAL_DPI, res.getHorizontalDpi());
-        proto.write(ResolutionProto.VERTICAL_DPI, res.getVerticalDpi());
+        long token = proto.start(idName, id);
+        proto.write("id", ResolutionProto.ID, res.getId());
+        proto.write("label", ResolutionProto.LABEL, res.getLabel());
+        proto.write("horizontal_DPI", ResolutionProto.HORIZONTAL_DPI, res.getHorizontalDpi());
+        proto.write("veritical_DPI", ResolutionProto.VERTICAL_DPI, res.getVerticalDpi());
         proto.end(token);
     }
 
@@ -202,16 +212,17 @@
      * Write a {@link PrintAttributes.Margins} to a proto.
      *
      * @param proto The proto to write to
+     * @param idName Clear text name of the proto-id
      * @param id The proto-id of the component name
      * @param margins The margins to write
      */
-    public static void writeMargins(@NonNull ProtoOutputStream proto, long id,
+    public static void writeMargins(@NonNull DualDumpOutputStream proto, String idName, long id,
             @NonNull PrintAttributes.Margins margins) {
-        long token = proto.start(id);
-        proto.write(MarginsProto.TOP_MILS, margins.getTopMils());
-        proto.write(MarginsProto.LEFT_MILS, margins.getLeftMils());
-        proto.write(MarginsProto.RIGHT_MILS, margins.getRightMils());
-        proto.write(MarginsProto.BOTTOM_MILS, margins.getBottomMils());
+        long token = proto.start(idName, id);
+        proto.write("top_mils", MarginsProto.TOP_MILS, margins.getTopMils());
+        proto.write("left_mils", MarginsProto.LEFT_MILS, margins.getLeftMils());
+        proto.write("right_mils", MarginsProto.RIGHT_MILS, margins.getRightMils());
+        proto.write("bottom_mils", MarginsProto.BOTTOM_MILS, margins.getBottomMils());
         proto.end(token);
     }
 
@@ -220,32 +231,34 @@
      *
      * @param context The context used to resolve resources
      * @param proto The proto to write to
+     * @param idName Clear text name of the proto-id
      * @param id The proto-id of the component name
      * @param attributes The attributes to write
      */
     public static void writePrintAttributes(@NonNull Context context,
-            @NonNull ProtoOutputStream proto, long id, @NonNull PrintAttributes attributes) {
-        long token = proto.start(id);
+            @NonNull DualDumpOutputStream proto, String idName, long id,
+            @NonNull PrintAttributes attributes) {
+        long token = proto.start(idName, id);
 
         PrintAttributes.MediaSize mediaSize = attributes.getMediaSize();
         if (mediaSize != null) {
-            writeMediaSize(context, proto, PrintAttributesProto.MEDIA_SIZE, mediaSize);
+            writeMediaSize(context, proto, "media_size", PrintAttributesProto.MEDIA_SIZE, mediaSize);
         }
 
-        proto.write(PrintAttributesProto.IS_PORTRAIT, attributes.isPortrait());
+        proto.write("is_portrait", PrintAttributesProto.IS_PORTRAIT, attributes.isPortrait());
 
         PrintAttributes.Resolution res = attributes.getResolution();
         if (res != null) {
-            writeResolution(proto, PrintAttributesProto.RESOLUTION, res);
+            writeResolution(proto, "resolution", PrintAttributesProto.RESOLUTION, res);
         }
 
         PrintAttributes.Margins minMargins = attributes.getMinMargins();
         if (minMargins != null) {
-            writeMargins(proto, PrintAttributesProto.MIN_MARGINS, minMargins);
+            writeMargins(proto, "min_margings", PrintAttributesProto.MIN_MARGINS, minMargins);
         }
 
-        proto.write(PrintAttributesProto.COLOR_MODE, attributes.getColorMode());
-        proto.write(PrintAttributesProto.DUPLEX_MODE, attributes.getDuplexMode());
+        proto.write("color_mode", PrintAttributesProto.COLOR_MODE, attributes.getColorMode());
+        proto.write("duplex_mode", PrintAttributesProto.DUPLEX_MODE, attributes.getDuplexMode());
         proto.end(token);
     }
 
@@ -253,21 +266,22 @@
      * Write a {@link PrintDocumentInfo} to a proto.
      *
      * @param proto The proto to write to
+     * @param idName Clear text name of the proto-id
      * @param id The proto-id of the component name
      * @param info The info to write
      */
-    public static void writePrintDocumentInfo(@NonNull ProtoOutputStream proto, long id,
-            @NonNull PrintDocumentInfo info) {
-        long token = proto.start(id);
-        proto.write(PrintDocumentInfoProto.NAME, info.getName());
+    public static void writePrintDocumentInfo(@NonNull DualDumpOutputStream proto, String idName,
+            long id, @NonNull PrintDocumentInfo info) {
+        long token = proto.start(idName, id);
+        proto.write("name", PrintDocumentInfoProto.NAME, info.getName());
 
         int pageCount = info.getPageCount();
         if (pageCount != PrintDocumentInfo.PAGE_COUNT_UNKNOWN) {
-            proto.write(PrintDocumentInfoProto.PAGE_COUNT, pageCount);
+            proto.write("page_count", PrintDocumentInfoProto.PAGE_COUNT, pageCount);
         }
 
-        proto.write(PrintDocumentInfoProto.CONTENT_TYPE, info.getContentType());
-        proto.write(PrintDocumentInfoProto.DATA_SIZE, info.getDataSize());
+        proto.write("content_type", PrintDocumentInfoProto.CONTENT_TYPE, info.getContentType());
+        proto.write("data_size", PrintDocumentInfoProto.DATA_SIZE, info.getDataSize());
         proto.end(token);
     }
 
@@ -275,14 +289,15 @@
      * Write a {@link PageRange} to a proto.
      *
      * @param proto The proto to write to
+     * @param idName Clear text name of the proto-id
      * @param id The proto-id of the component name
      * @param range The range to write
      */
-    public static void writePageRange(@NonNull ProtoOutputStream proto, long id,
+    public static void writePageRange(@NonNull DualDumpOutputStream proto, String idName, long id,
             @NonNull PageRange range) {
-        long token = proto.start(id);
-        proto.write(PageRangeProto.START, range.getStart());
-        proto.write(PageRangeProto.END, range.getEnd());
+        long token = proto.start(idName, id);
+        proto.write("start", PageRangeProto.START, range.getStart());
+        proto.write("end", PageRangeProto.END, range.getEnd());
         proto.end(token);
     }
 
@@ -291,64 +306,70 @@
      *
      * @param context The context used to resolve resources
      * @param proto The proto to write to
+     * @param idName Clear text name of the proto-id
      * @param id The proto-id of the component name
      * @param printJobInfo The print job info to write
      */
-    public static void writePrintJobInfo(@NonNull Context context, @NonNull ProtoOutputStream proto,
-            long id, @NonNull PrintJobInfo printJobInfo) {
-        long token = proto.start(id);
-        proto.write(PrintJobInfoProto.LABEL, printJobInfo.getLabel());
+    public static void writePrintJobInfo(@NonNull Context context,
+            @NonNull DualDumpOutputStream proto, String idName, long id,
+            @NonNull PrintJobInfo printJobInfo) {
+        long token = proto.start(idName, id);
+        proto.write("label", PrintJobInfoProto.LABEL, printJobInfo.getLabel());
 
         PrintJobId printJobId = printJobInfo.getId();
         if (printJobId != null) {
-            proto.write(PrintJobInfoProto.PRINT_JOB_ID, printJobId.flattenToString());
+            proto.write("print_job_id", PrintJobInfoProto.PRINT_JOB_ID,
+                    printJobId.flattenToString());
         }
 
         int state = printJobInfo.getState();
         if (state >= PrintJobInfoProto.STATE_CREATED && state <= PrintJobInfoProto.STATE_CANCELED) {
-            proto.write(PrintJobInfoProto.STATE, state);
+            proto.write("state", PrintJobInfoProto.STATE, state);
         } else {
-            proto.write(PrintJobInfoProto.STATE, PrintJobInfoProto.STATE_UNKNOWN);
+            proto.write("state", PrintJobInfoProto.STATE, PrintJobInfoProto.STATE_UNKNOWN);
         }
 
         PrinterId printer = printJobInfo.getPrinterId();
         if (printer != null) {
-            writePrinterId(proto, PrintJobInfoProto.PRINTER, printer);
+            writePrinterId(proto, "printer", PrintJobInfoProto.PRINTER, printer);
         }
 
         String tag = printJobInfo.getTag();
         if (tag != null) {
-            proto.write(PrintJobInfoProto.TAG, tag);
+            proto.write("tag", PrintJobInfoProto.TAG, tag);
         }
 
-        proto.write(PrintJobInfoProto.CREATION_TIME, printJobInfo.getCreationTime());
+        proto.write("creation_time", PrintJobInfoProto.CREATION_TIME,
+                printJobInfo.getCreationTime());
 
         PrintAttributes attributes = printJobInfo.getAttributes();
         if (attributes != null) {
-            writePrintAttributes(context, proto, PrintJobInfoProto.ATTRIBUTES, attributes);
+            writePrintAttributes(context, proto, "attributes", PrintJobInfoProto.ATTRIBUTES,
+                    attributes);
         }
 
         PrintDocumentInfo docInfo = printJobInfo.getDocumentInfo();
         if (docInfo != null) {
-            writePrintDocumentInfo(proto, PrintJobInfoProto.DOCUMENT_INFO, docInfo);
+            writePrintDocumentInfo(proto, "document_info", PrintJobInfoProto.DOCUMENT_INFO,
+                    docInfo);
         }
 
-        proto.write(PrintJobInfoProto.IS_CANCELING, printJobInfo.isCancelling());
+        proto.write("is_canceling", PrintJobInfoProto.IS_CANCELING, printJobInfo.isCancelling());
 
         PageRange[] pages = printJobInfo.getPages();
         if (pages != null) {
             for (int i = 0; i < pages.length; i++) {
-                writePageRange(proto, PrintJobInfoProto.PAGES, pages[i]);
+                writePageRange(proto, "pages", PrintJobInfoProto.PAGES, pages[i]);
             }
         }
 
-        proto.write(PrintJobInfoProto.HAS_ADVANCED_OPTIONS,
+        proto.write("has_advanced_options", PrintJobInfoProto.HAS_ADVANCED_OPTIONS,
                 printJobInfo.getAdvancedOptions() != null);
-        proto.write(PrintJobInfoProto.PROGRESS, printJobInfo.getProgress());
+        proto.write("progress", PrintJobInfoProto.PROGRESS, printJobInfo.getProgress());
 
         CharSequence status = printJobInfo.getStatus(context.getPackageManager());
         if (status != null) {
-            proto.write(PrintJobInfoProto.STATUS, status.toString());
+            proto.write("status", PrintJobInfoProto.STATUS, status.toString());
         }
 
         proto.end(token);
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
index e0a3f6c..074f9ef 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
@@ -59,7 +59,9 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.os.HandlerCaller;
+import com.android.internal.print.DualDumpOutputStream;
 import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
 import com.android.printspooler.R;
 import com.android.printspooler.util.ApprovedPrintServices;
@@ -159,43 +161,10 @@
         return new PrintSpooler();
     }
 
-    private void dumpLocked(PrintWriter pw, String[] args) {
-        String prefix = (args.length > 0) ? args[0] : "";
-        String tab = "  ";
-
-        pw.append(prefix).append("print jobs:").println();
-        final int printJobCount = mPrintJobs.size();
-        for (int i = 0; i < printJobCount; i++) {
-            PrintJobInfo printJob = mPrintJobs.get(i);
-            pw.append(prefix).append(tab).append(printJob.toString());
-            pw.println();
-        }
-
-        pw.append(prefix).append("print job files:").println();
-        File[] files = getFilesDir().listFiles();
-        if (files != null) {
-            final int fileCount = files.length;
-            for (int i = 0; i < fileCount; i++) {
-                File file = files[i];
-                if (file.isFile() && file.getName().startsWith(PRINT_JOB_FILE_PREFIX)) {
-                    pw.append(prefix).append(tab).append(file.getName()).println();
-                }
-            }
-        }
-
-        pw.append(prefix).append("approved print services:").println();
-        Set<String> approvedPrintServices = (new ApprovedPrintServices(this)).getApprovedServices();
-        if (approvedPrintServices != null) {
-            for (String approvedService : approvedPrintServices) {
-                pw.append(prefix).append(tab).append(approvedService).println();
-            }
-        }
-    }
-
-    private void dumpLocked(@NonNull ProtoOutputStream proto) {
+    private void dumpLocked(@NonNull DualDumpOutputStream proto) {
         int numPrintJobs = mPrintJobs.size();
         for (int i = 0; i < numPrintJobs; i++) {
-            writePrintJobInfo(this, proto, PrintSpoolerInternalStateProto.PRINT_JOBS,
+            writePrintJobInfo(this, proto, "print_jobs", PrintSpoolerInternalStateProto.PRINT_JOBS,
                     mPrintJobs.get(i));
         }
 
@@ -204,7 +173,8 @@
             for (int i = 0; i < files.length; i++) {
                 File file = files[i];
                 if (file.isFile() && file.getName().startsWith(PRINT_JOB_FILE_PREFIX)) {
-                    proto.write(PrintSpoolerInternalStateProto.PRINT_JOB_FILES, file.getName());
+                    proto.write("print_job_files", PrintSpoolerInternalStateProto.PRINT_JOB_FILES,
+                            file.getName());
                 }
             }
         }
@@ -214,8 +184,8 @@
             for (String approvedService : approvedPrintServices) {
                 ComponentName componentName = ComponentName.unflattenFromString(approvedService);
                 if (componentName != null) {
-                    writeComponentName(proto, PrintSpoolerInternalStateProto.APPROVED_SERVICES,
-                            componentName);
+                    writeComponentName(proto, "approved_services",
+                            PrintSpoolerInternalStateProto.APPROVED_SERVICES, componentName);
                 }
             }
         }
@@ -244,9 +214,15 @@
         try {
             synchronized (mLock) {
                 if (dumpAsProto) {
-                    dumpLocked(new ProtoOutputStream(fd));
+                    dumpLocked(new DualDumpOutputStream(new ProtoOutputStream(fd), null));
                 } else {
-                    dumpLocked(pw, args);
+                    try (FileOutputStream out = new FileOutputStream(fd)) {
+                        try (PrintWriter w = new PrintWriter(out)) {
+                            dumpLocked(new DualDumpOutputStream(null, new IndentingPrintWriter(w,
+                                    "  ")));
+                        }
+                    } catch (IOException ignored) {
+                    }
                 }
             }
         } finally {
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index 71ba685..1dc9d26 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -57,7 +57,9 @@
 
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.os.BackgroundThread;
+import com.android.internal.print.DualDumpOutputStream;
 import com.android.internal.util.DumpUtils;
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
 import com.android.server.SystemService;
 
@@ -670,20 +672,24 @@
             final long identity = Binder.clearCallingIdentity();
             try {
                 if (dumpAsProto) {
-                    dump(new ProtoOutputStream(fd), userStatesToDump);
+                    dump(new DualDumpOutputStream(new ProtoOutputStream(fd), null),
+                            userStatesToDump);
                 } else {
-                    dump(fd, pw, userStatesToDump);
+                    pw.println("PRINT MANAGER STATE (dumpsys print)");
+
+                    dump(new DualDumpOutputStream(null, new IndentingPrintWriter(pw, "  ")),
+                            userStatesToDump);
                 }
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
         }
 
-        private void dump(@NonNull ProtoOutputStream proto,
+        private void dump(@NonNull DualDumpOutputStream proto,
                 @NonNull ArrayList<UserState> userStatesToDump) {
             final int userStateCount = userStatesToDump.size();
             for (int i = 0; i < userStateCount; i++) {
-                long token = proto.start(PrintServiceDumpProto.USER_STATES);
+                long token = proto.start("user_states", PrintServiceDumpProto.USER_STATES);
                 userStatesToDump.get(i).dump(proto);
                 proto.end(token);
             }
@@ -691,18 +697,6 @@
             proto.flush();
         }
 
-        private void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw,
-                @NonNull ArrayList<UserState> userStatesToDump) {
-            pw = Preconditions.checkNotNull(pw);
-
-            pw.println("PRINT MANAGER STATE (dumpsys print)");
-            final int userStateCount = userStatesToDump.size();
-            for (int i = 0; i < userStateCount; i++) {
-                userStatesToDump.get(i).dump(fd, pw, "");
-                pw.println();
-            }
-        }
-
         private void registerContentObservers() {
             final Uri enabledPrintServicesUri = Settings.Secure.getUriFor(
                     Settings.Secure.DISABLED_PRINT_SERVICES);
diff --git a/services/print/java/com/android/server/print/RemotePrintService.java b/services/print/java/com/android/server/print/RemotePrintService.java
index 13462cd..80b97cf 100644
--- a/services/print/java/com/android/server/print/RemotePrintService.java
+++ b/services/print/java/com/android/server/print/RemotePrintService.java
@@ -47,11 +47,10 @@
 import android.printservice.IPrintServiceClient;
 import android.service.print.ActivePrintServiceProto;
 import android.util.Slog;
-import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.print.DualDumpOutputStream;
 
-import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
@@ -532,49 +531,30 @@
         }
     }
 
-    public void dump(@NonNull ProtoOutputStream proto) {
-        writeComponentName(proto, ActivePrintServiceProto.COMPONENT_NAME, mComponentName);
+    public void dump(@NonNull DualDumpOutputStream proto) {
+        writeComponentName(proto, "component_name", ActivePrintServiceProto.COMPONENT_NAME,
+                mComponentName);
 
-        proto.write(ActivePrintServiceProto.IS_DESTROYED, mDestroyed);
-        proto.write(ActivePrintServiceProto.IS_BOUND, isBound());
-        proto.write(ActivePrintServiceProto.HAS_DISCOVERY_SESSION, mHasPrinterDiscoverySession);
-        proto.write(ActivePrintServiceProto.HAS_ACTIVE_PRINT_JOBS, mHasActivePrintJobs);
-        proto.write(ActivePrintServiceProto.IS_DISCOVERING_PRINTERS,
+        proto.write("is_destroyed", ActivePrintServiceProto.IS_DESTROYED, mDestroyed);
+        proto.write("is_bound", ActivePrintServiceProto.IS_BOUND, isBound());
+        proto.write("has_discovery_session", ActivePrintServiceProto.HAS_DISCOVERY_SESSION,
+                mHasPrinterDiscoverySession);
+        proto.write("has_active_print_jobs", ActivePrintServiceProto.HAS_ACTIVE_PRINT_JOBS,
+                mHasActivePrintJobs);
+        proto.write("is_discovering_printers", ActivePrintServiceProto.IS_DISCOVERING_PRINTERS,
                 mDiscoveryPriorityList != null);
 
         synchronized (mLock) {
             if (mTrackedPrinterList != null) {
                 int numTrackedPrinters = mTrackedPrinterList.size();
                 for (int i = 0; i < numTrackedPrinters; i++) {
-                    writePrinterId(proto, ActivePrintServiceProto.TRACKED_PRINTERS,
-                            mTrackedPrinterList.get(i));
+                    writePrinterId(proto, "tracked_printers",
+                            ActivePrintServiceProto.TRACKED_PRINTERS, mTrackedPrinterList.get(i));
                 }
             }
         }
     }
 
-    public void dump(PrintWriter pw, String prefix) {
-        String tab = "  ";
-        pw.append(prefix).append("service:").println();
-        pw.append(prefix).append(tab).append("componentName=")
-                .append(mComponentName.flattenToString()).println();
-        pw.append(prefix).append(tab).append("destroyed=")
-                .append(String.valueOf(mDestroyed)).println();
-        pw.append(prefix).append(tab).append("bound=")
-                .append(String.valueOf(isBound())).println();
-        pw.append(prefix).append(tab).append("hasDicoverySession=")
-                .append(String.valueOf(mHasPrinterDiscoverySession)).println();
-        pw.append(prefix).append(tab).append("hasActivePrintJobs=")
-                .append(String.valueOf(mHasActivePrintJobs)).println();
-        pw.append(prefix).append(tab).append("isDiscoveringPrinters=")
-                .append(String.valueOf(mDiscoveryPriorityList != null)).println();
-
-        synchronized (mLock) {
-            pw.append(prefix).append(tab).append("trackedPrinters=").append(
-                    (mTrackedPrinterList != null) ? mTrackedPrinterList.toString() : "null");
-        }
-    }
-
     private boolean isBound() {
         return mPrintService != null;
     }
diff --git a/services/print/java/com/android/server/print/RemotePrintSpooler.java b/services/print/java/com/android/server/print/RemotePrintSpooler.java
index f654fcb..5520255 100644
--- a/services/print/java/com/android/server/print/RemotePrintSpooler.java
+++ b/services/print/java/com/android/server/print/RemotePrintSpooler.java
@@ -43,16 +43,14 @@
 import android.service.print.PrintSpoolerStateProto;
 import android.util.Slog;
 import android.util.TimedRemoteCaller;
-import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.os.TransferPipe;
+import com.android.internal.print.DualDumpOutputStream;
 
 import libcore.io.IoUtils;
 
-import java.io.FileDescriptor;
 import java.io.IOException;
-import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.List;
 import java.util.concurrent.TimeoutException;
@@ -558,37 +556,25 @@
         }
     }
 
-    public void dump(@NonNull ProtoOutputStream proto) {
+    public void dump(@NonNull DualDumpOutputStream proto) {
         synchronized (mLock) {
-            proto.write(PrintSpoolerStateProto.IS_DESTROYED, mDestroyed);
-            proto.write(PrintSpoolerStateProto.IS_BOUND, mRemoteInstance != null);
+            proto.write("is_destroyed", PrintSpoolerStateProto.IS_DESTROYED, mDestroyed);
+            proto.write("is_bound", PrintSpoolerStateProto.IS_BOUND, mRemoteInstance != null);
         }
 
         try {
-            proto.write(PrintSpoolerStateProto.INTERNAL_STATE,
-                    TransferPipe.dumpAsync(getRemoteInstanceLazy().asBinder(), "--proto"));
+            if (proto.isProto()) {
+                proto.write(null, PrintSpoolerStateProto.INTERNAL_STATE,
+                        TransferPipe.dumpAsync(getRemoteInstanceLazy().asBinder(), "--proto"));
+            } else {
+                proto.writeNested("internal_state", TransferPipe.dumpAsync(
+                        getRemoteInstanceLazy().asBinder()));
+            }
         } catch (IOException | TimeoutException | RemoteException | InterruptedException e) {
             Slog.e(LOG_TAG, "Failed to dump remote instance", e);
         }
     }
 
-    public void dump(FileDescriptor fd, PrintWriter pw, String prefix) {
-        synchronized (mLock) {
-            pw.append(prefix).append("destroyed=")
-                    .append(String.valueOf(mDestroyed)).println();
-            pw.append(prefix).append("bound=")
-                    .append((mRemoteInstance != null) ? "true" : "false").println();
-
-            pw.flush();
-            try {
-                TransferPipe.dumpAsync(getRemoteInstanceLazy().asBinder(), fd,
-                        new String[] { prefix });
-            } catch (IOException | TimeoutException | RemoteException | InterruptedException e) {
-                pw.println("Failed to dump remote instance: " + e);
-            }
-        }
-    }
-
     private void onAllPrintJobsHandled() {
         synchronized (mLock) {
             throwIfDestroyedLocked();
diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
index 364bbc0..318e481 100644
--- a/services/print/java/com/android/server/print/UserState.java
+++ b/services/print/java/com/android/server/print/UserState.java
@@ -76,19 +76,17 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
-import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.R;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.os.BackgroundThread;
+import com.android.internal.print.DualDumpOutputStream;
 import com.android.server.print.RemotePrintService.PrintServiceCallbacks;
 import com.android.server.print.RemotePrintServiceRecommendationService
         .RemotePrintServiceRecommendationServiceCallbacks;
 import com.android.server.print.RemotePrintSpooler.PrintSpoolerCallbacks;
 
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
@@ -817,37 +815,43 @@
         mDestroyed = true;
     }
 
-    public void dump(@NonNull ProtoOutputStream proto) {
+    public void dump(@NonNull DualDumpOutputStream proto) {
         synchronized (mLock) {
-            proto.write(PrintUserStateProto.USER_ID, mUserId);
+            proto.write("user_id", PrintUserStateProto.USER_ID, mUserId);
 
             final int installedServiceCount = mInstalledServices.size();
             for (int i = 0; i < installedServiceCount; i++) {
-                long token = proto.start(PrintUserStateProto.INSTALLED_SERVICES);
+                long token = proto.start("installed_services",
+                        PrintUserStateProto.INSTALLED_SERVICES);
                 PrintServiceInfo installedService = mInstalledServices.get(i);
 
                 ResolveInfo resolveInfo = installedService.getResolveInfo();
-                writeComponentName(proto, InstalledPrintServiceProto.COMPONENT_NAME,
+                writeComponentName(proto, "component_name",
+                        InstalledPrintServiceProto.COMPONENT_NAME,
                         new ComponentName(resolveInfo.serviceInfo.packageName,
                                 resolveInfo.serviceInfo.name));
 
-                writeStringIfNotNull(proto, InstalledPrintServiceProto.SETTINGS_ACTIVITY,
+                writeStringIfNotNull(proto, "settings_activity",
+                        InstalledPrintServiceProto.SETTINGS_ACTIVITY,
                         installedService.getSettingsActivityName());
-                writeStringIfNotNull(proto, InstalledPrintServiceProto.ADD_PRINTERS_ACTIVITY,
+                writeStringIfNotNull(proto, "add_printers_activity",
+                        InstalledPrintServiceProto.ADD_PRINTERS_ACTIVITY,
                         installedService.getAddPrintersActivityName());
-                writeStringIfNotNull(proto, InstalledPrintServiceProto.ADVANCED_OPTIONS_ACTIVITY,
+                writeStringIfNotNull(proto, "advanced_options_activity",
+                        InstalledPrintServiceProto.ADVANCED_OPTIONS_ACTIVITY,
                         installedService.getAdvancedOptionsActivityName());
 
                 proto.end(token);
             }
 
             for (ComponentName disabledService : mDisabledServices) {
-                writeComponentName(proto, PrintUserStateProto.DISABLED_SERVICES, disabledService);
+                writeComponentName(proto, "disabled_services",
+                        PrintUserStateProto.DISABLED_SERVICES, disabledService);
             }
 
             final int activeServiceCount = mActiveServices.size();
             for (int i = 0; i < activeServiceCount; i++) {
-                long token = proto.start(PrintUserStateProto.ACTIVE_SERVICES);
+                long token = proto.start("actives_services", PrintUserStateProto.ACTIVE_SERVICES);
                 mActiveServices.valueAt(i).dump(proto);
                 proto.end(token);
             }
@@ -855,76 +859,19 @@
             mPrintJobForAppCache.dumpLocked(proto);
 
             if (mPrinterDiscoverySession != null) {
-                long token = proto.start(PrintUserStateProto.DISCOVERY_SESSIONS);
+                long token = proto.start("discovery_service",
+                        PrintUserStateProto.DISCOVERY_SESSIONS);
                 mPrinterDiscoverySession.dumpLocked(proto);
                 proto.end(token);
             }
 
         }
 
-        long token = proto.start(PrintUserStateProto.PRINT_SPOOLER_STATE);
+        long token = proto.start("print_spooler_state", PrintUserStateProto.PRINT_SPOOLER_STATE);
         mSpooler.dump(proto);
         proto.end(token);
     }
 
-    public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String prefix) {
-        pw.append(prefix).append("user state ").append(String.valueOf(mUserId)).append(":");
-        pw.println();
-
-        String tab = "  ";
-
-        synchronized (mLock) {
-            pw.append(prefix).append(tab).append("installed services:").println();
-            final int installedServiceCount = mInstalledServices.size();
-            for (int i = 0; i < installedServiceCount; i++) {
-                PrintServiceInfo installedService = mInstalledServices.get(i);
-                String installedServicePrefix = prefix + tab + tab;
-                pw.append(installedServicePrefix).append("service:").println();
-                ResolveInfo resolveInfo = installedService.getResolveInfo();
-                ComponentName componentName = new ComponentName(
-                        resolveInfo.serviceInfo.packageName,
-                        resolveInfo.serviceInfo.name);
-                pw.append(installedServicePrefix).append(tab).append("componentName=")
-                        .append(componentName.flattenToString()).println();
-                pw.append(installedServicePrefix).append(tab).append("settingsActivity=")
-                        .append(installedService.getSettingsActivityName()).println();
-                pw.append(installedServicePrefix).append(tab).append("addPrintersActivity=")
-                        .append(installedService.getAddPrintersActivityName()).println();
-                pw.append(installedServicePrefix).append(tab).append("avancedOptionsActivity=")
-                        .append(installedService.getAdvancedOptionsActivityName()).println();
-            }
-
-            pw.append(prefix).append(tab).append("disabled services:").println();
-            for (ComponentName disabledService : mDisabledServices) {
-                String disabledServicePrefix = prefix + tab + tab;
-                pw.append(disabledServicePrefix).append("service:").println();
-                pw.append(disabledServicePrefix).append(tab).append("componentName=")
-                        .append(disabledService.flattenToString());
-                pw.println();
-            }
-
-            pw.append(prefix).append(tab).append("active services:").println();
-            final int activeServiceCount = mActiveServices.size();
-            for (int i = 0; i < activeServiceCount; i++) {
-                RemotePrintService activeService = mActiveServices.valueAt(i);
-                activeService.dump(pw, prefix + tab + tab);
-                pw.println();
-            }
-
-            pw.append(prefix).append(tab).append("cached print jobs:").println();
-            mPrintJobForAppCache.dumpLocked(pw, prefix + tab + tab);
-
-            pw.append(prefix).append(tab).append("discovery mediator:").println();
-            if (mPrinterDiscoverySession != null) {
-                mPrinterDiscoverySession.dumpLocked(pw, prefix + tab + tab);
-            }
-        }
-
-        pw.append(prefix).append(tab).append("print spooler:").println();
-        mSpooler.dump(fd, pw, prefix + tab + tab);
-        pw.println();
-    }
-
     private void readConfigurationLocked() {
         readInstalledPrintServicesLocked();
         readDisabledPrintServicesLocked();
@@ -1650,15 +1597,17 @@
             }
         }
 
-        public void dumpLocked(@NonNull ProtoOutputStream proto) {
-            proto.write(PrinterDiscoverySessionProto.IS_DESTROYED, mDestroyed);
-            proto.write(PrinterDiscoverySessionProto.IS_PRINTER_DISCOVERY_IN_PROGRESS,
+        public void dumpLocked(@NonNull DualDumpOutputStream proto) {
+            proto.write("is_destroyed", PrinterDiscoverySessionProto.IS_DESTROYED, mDestroyed);
+            proto.write("is_printer_discovery_in_progress",
+                    PrinterDiscoverySessionProto.IS_PRINTER_DISCOVERY_IN_PROGRESS,
                     !mStartedPrinterDiscoveryTokens.isEmpty());
 
             final int observerCount = mDiscoveryObservers.beginBroadcast();
             for (int i = 0; i < observerCount; i++) {
                 IPrinterDiscoveryObserver observer = mDiscoveryObservers.getBroadcastItem(i);
-                proto.write(PrinterDiscoverySessionProto.PRINTER_DISCOVERY_OBSERVERS,
+                proto.write("printer_discovery_observers",
+                        PrinterDiscoverySessionProto.PRINTER_DISCOVERY_OBSERVERS,
                         observer.toString());
             }
             mDiscoveryObservers.finishBroadcast();
@@ -1666,61 +1615,22 @@
             final int tokenCount = this.mStartedPrinterDiscoveryTokens.size();
             for (int i = 0; i < tokenCount; i++) {
                 IBinder token = mStartedPrinterDiscoveryTokens.get(i);
-                proto.write(PrinterDiscoverySessionProto.DISCOVERY_REQUESTS, token.toString());
+                proto.write("discovery_requests",
+                        PrinterDiscoverySessionProto.DISCOVERY_REQUESTS, token.toString());
             }
 
             final int trackedPrinters = mStateTrackedPrinters.size();
             for (int i = 0; i < trackedPrinters; i++) {
                 PrinterId printer = mStateTrackedPrinters.get(i);
-                writePrinterId(proto, PrinterDiscoverySessionProto.TRACKED_PRINTER_REQUESTS,
-                        printer);
+                writePrinterId(proto, "tracked_printer_requests",
+                        PrinterDiscoverySessionProto.TRACKED_PRINTER_REQUESTS, printer);
             }
 
             final int printerCount = mPrinters.size();
             for (int i = 0; i < printerCount; i++) {
                 PrinterInfo printer = mPrinters.valueAt(i);
-                writePrinterInfo(mContext, proto, PrinterDiscoverySessionProto.PRINTER, printer);
-            }
-        }
-
-        public void dumpLocked(PrintWriter pw, String prefix) {
-            pw.append(prefix).append("destroyed=")
-                    .append(String.valueOf(mDestroyed)).println();
-
-            pw.append(prefix).append("printDiscoveryInProgress=")
-                    .append(String.valueOf(!mStartedPrinterDiscoveryTokens.isEmpty())).println();
-
-            String tab = "  ";
-
-            pw.append(prefix).append(tab).append("printer discovery observers:").println();
-            final int observerCount = mDiscoveryObservers.beginBroadcast();
-            for (int i = 0; i < observerCount; i++) {
-                IPrinterDiscoveryObserver observer = mDiscoveryObservers.getBroadcastItem(i);
-                pw.append(prefix).append(prefix).append(observer.toString());
-                pw.println();
-            }
-            mDiscoveryObservers.finishBroadcast();
-
-            pw.append(prefix).append(tab).append("start discovery requests:").println();
-            final int tokenCount = this.mStartedPrinterDiscoveryTokens.size();
-            for (int i = 0; i < tokenCount; i++) {
-                IBinder token = mStartedPrinterDiscoveryTokens.get(i);
-                pw.append(prefix).append(tab).append(tab).append(token.toString()).println();
-            }
-
-            pw.append(prefix).append(tab).append("tracked printer requests:").println();
-            final int trackedPrinters = mStateTrackedPrinters.size();
-            for (int i = 0; i < trackedPrinters; i++) {
-                PrinterId printer = mStateTrackedPrinters.get(i);
-                pw.append(prefix).append(tab).append(tab).append(printer.toString()).println();
-            }
-
-            pw.append(prefix).append(tab).append("printers:").println();
-            final int pritnerCount = mPrinters.size();
-            for (int i = 0; i < pritnerCount; i++) {
-                PrinterInfo printer = mPrinters.valueAt(i);
-                pw.append(prefix).append(tab).append(tab).append(
-                        printer.toString()).println();
+                writePrinterInfo(mContext, proto, "printer",
+                        PrinterDiscoverySessionProto.PRINTER, printer);
             }
         }
 
@@ -1933,33 +1843,19 @@
             }
         }
 
-        public void dumpLocked(PrintWriter pw, String prefix) {
-            String tab = "  ";
-            final int bucketCount = mPrintJobsForRunningApp.size();
-            for (int i = 0; i < bucketCount; i++) {
-                final int appId = mPrintJobsForRunningApp.keyAt(i);
-                pw.append(prefix).append("appId=" + appId).append(':').println();
-                List<PrintJobInfo> bucket = mPrintJobsForRunningApp.valueAt(i);
-                final int printJobCount = bucket.size();
-                for (int j = 0; j < printJobCount; j++) {
-                    PrintJobInfo printJob = bucket.get(j);
-                    pw.append(prefix).append(tab).append(printJob.toString()).println();
-                }
-            }
-        }
-
-        public void dumpLocked(@NonNull ProtoOutputStream proto) {
+        public void dumpLocked(@NonNull DualDumpOutputStream proto) {
             final int bucketCount = mPrintJobsForRunningApp.size();
             for (int i = 0; i < bucketCount; i++) {
                 final int appId = mPrintJobsForRunningApp.keyAt(i);
                 List<PrintJobInfo> bucket = mPrintJobsForRunningApp.valueAt(i);
                 final int printJobCount = bucket.size();
                 for (int j = 0; j < printJobCount; j++) {
-                    long token = proto.start(PrintUserStateProto.CACHED_PRINT_JOBS);
+                    long token = proto.start("cached_print_jobs",
+                            PrintUserStateProto.CACHED_PRINT_JOBS);
 
-                    proto.write(CachedPrintJobProto.APP_ID, appId);
+                    proto.write("app_id", CachedPrintJobProto.APP_ID, appId);
 
-                    writePrintJobInfo(mContext, proto, CachedPrintJobProto.PRINT_JOB,
+                    writePrintJobInfo(mContext, proto, "print_job", CachedPrintJobProto.PRINT_JOB,
                             bucket.get(j));
 
                     proto.end(token);