diff options
12 files changed, 1192 insertions, 130 deletions
diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java index 17942aea960a..ce5b11ee33f1 100644 --- a/core/java/android/print/PrintAttributes.java +++ b/core/java/android/print/PrintAttributes.java @@ -26,6 +26,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources.NotFoundException; import android.os.Parcel; import android.os.Parcelable; +import android.service.print.PrintAttributesProto; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; @@ -54,9 +55,9 @@ public final class PrintAttributes implements Parcelable { @interface ColorMode { } /** Color mode: Monochrome color scheme, for example one color is used. */ - public static final int COLOR_MODE_MONOCHROME = 1 << 0; + public static final int COLOR_MODE_MONOCHROME = PrintAttributesProto.COLOR_MODE_MONOCHROME; /** Color mode: Color color scheme, for example many colors are used. */ - public static final int COLOR_MODE_COLOR = 1 << 1; + public static final int COLOR_MODE_COLOR = PrintAttributesProto.COLOR_MODE_COLOR; private static final int VALID_COLOR_MODES = COLOR_MODE_MONOCHROME | COLOR_MODE_COLOR; @@ -69,11 +70,11 @@ public final class PrintAttributes implements Parcelable { @interface DuplexMode { } /** Duplex mode: No duplexing. */ - public static final int DUPLEX_MODE_NONE = 1 << 0; + public static final int DUPLEX_MODE_NONE = PrintAttributesProto.DUPLEX_MODE_NONE; /** Duplex mode: Pages are turned sideways along the long edge - like a book. */ - public static final int DUPLEX_MODE_LONG_EDGE = 1 << 1; + public static final int DUPLEX_MODE_LONG_EDGE = PrintAttributesProto.DUPLEX_MODE_LONG_EDGE; /** Duplex mode: Pages are turned upwards along the short edge - like a notpad. */ - public static final int DUPLEX_MODE_SHORT_EDGE = 1 << 2; + public static final int DUPLEX_MODE_SHORT_EDGE = PrintAttributesProto.DUPLEX_MODE_SHORT_EDGE; private static final int VALID_DUPLEX_MODES = DUPLEX_MODE_NONE | DUPLEX_MODE_LONG_EDGE | DUPLEX_MODE_SHORT_EDGE; diff --git a/core/java/android/print/PrintJobInfo.java b/core/java/android/print/PrintJobInfo.java index 3d094f7d09f4..94686a8ee456 100644 --- a/core/java/android/print/PrintJobInfo.java +++ b/core/java/android/print/PrintJobInfo.java @@ -28,6 +28,7 @@ import android.content.res.Resources; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; +import android.service.print.PrintJobInfoProto; import com.android.internal.util.Preconditions; @@ -88,7 +89,7 @@ public final class PrintJobInfo implements Parcelable { * Next valid states: {@link #STATE_QUEUED} * </p> */ - public static final int STATE_CREATED = 1; + public static final int STATE_CREATED = PrintJobInfoProto.STATE_CREATED; /** * Print job state: The print jobs is created, it is ready @@ -98,7 +99,7 @@ public final class PrintJobInfo implements Parcelable { * {@link #STATE_CANCELED} * </p> */ - public static final int STATE_QUEUED = 2; + public static final int STATE_QUEUED = PrintJobInfoProto.STATE_QUEUED; /** * Print job state: The print job is being printed. @@ -107,7 +108,7 @@ public final class PrintJobInfo implements Parcelable { * {@link #STATE_CANCELED}, {@link #STATE_BLOCKED} * </p> */ - public static final int STATE_STARTED = 3; + public static final int STATE_STARTED = PrintJobInfoProto.STATE_STARTED; /** * Print job state: The print job is blocked. @@ -116,7 +117,7 @@ public final class PrintJobInfo implements Parcelable { * {@link #STATE_STARTED} * </p> */ - public static final int STATE_BLOCKED = 4; + public static final int STATE_BLOCKED = PrintJobInfoProto.STATE_BLOCKED; /** * Print job state: The print job is successfully printed. @@ -125,7 +126,7 @@ public final class PrintJobInfo implements Parcelable { * Next valid states: None * </p> */ - public static final int STATE_COMPLETED = 5; + public static final int STATE_COMPLETED = PrintJobInfoProto.STATE_COMPLETED; /** * Print job state: The print job was printing but printing failed. @@ -133,7 +134,7 @@ public final class PrintJobInfo implements Parcelable { * Next valid states: {@link #STATE_CANCELED}, {@link #STATE_STARTED} * </p> */ - public static final int STATE_FAILED = 6; + public static final int STATE_FAILED = PrintJobInfoProto.STATE_FAILED; /** * Print job state: The print job is canceled. @@ -142,7 +143,7 @@ public final class PrintJobInfo implements Parcelable { * Next valid states: None * </p> */ - public static final int STATE_CANCELED = 7; + public static final int STATE_CANCELED = PrintJobInfoProto.STATE_CANCELED; /** The unique print job id. */ private PrintJobId mId; diff --git a/core/java/android/print/PrinterInfo.java b/core/java/android/print/PrinterInfo.java index f99b185229bc..88feab7fc2ca 100644 --- a/core/java/android/print/PrinterInfo.java +++ b/core/java/android/print/PrinterInfo.java @@ -31,6 +31,7 @@ import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.os.Parcel; import android.os.Parcelable; +import android.service.print.PrinterInfoProto; import android.text.TextUtils; import com.android.internal.util.Preconditions; @@ -59,13 +60,13 @@ public final class PrinterInfo implements Parcelable { public @interface Status { } /** Printer status: the printer is idle and ready to print. */ - public static final int STATUS_IDLE = 1; + public static final int STATUS_IDLE = PrinterInfoProto.STATUS_IDLE; /** Printer status: the printer is busy printing. */ - public static final int STATUS_BUSY = 2; + public static final int STATUS_BUSY = PrinterInfoProto.STATUS_BUSY; /** Printer status: the printer is not available. */ - public static final int STATUS_UNAVAILABLE = 3; + public static final int STATUS_UNAVAILABLE = PrinterInfoProto.STATUS_UNAVAILABLE; private final @NonNull PrinterId mId; diff --git a/core/java/com/android/internal/os/TransferPipe.java b/core/java/com/android/internal/os/TransferPipe.java index f9041507ffdd..738ecc0bdaa0 100644 --- a/core/java/com/android/internal/os/TransferPipe.java +++ b/core/java/com/android/internal/os/TransferPipe.java @@ -16,12 +16,8 @@ package com.android.internal.os; -import java.io.Closeable; -import java.io.FileDescriptor; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; - +import android.annotation.NonNull; +import android.annotation.Nullable; import android.os.Binder; import android.os.IBinder; import android.os.IInterface; @@ -30,6 +26,15 @@ import android.os.RemoteException; import android.os.SystemClock; import android.util.Slog; +import libcore.io.IoUtils; + +import java.io.ByteArrayOutputStream; +import java.io.Closeable; +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; + /** * Helper for transferring data through a pipe from a client app. */ @@ -81,6 +86,45 @@ public final class TransferPipe implements Runnable, Closeable { goDump(binder, out, args); } + /** + * Read raw bytes from a service's dump function. + * + * <p>This can be used for dumping {@link android.util.proto.ProtoOutputStream protos}. + * + * @param binder The service providing the data + * @param args The arguments passed to the dump function of the service + */ + public static byte[] dumpAsync(@NonNull IBinder binder, @Nullable String... args) + throws IOException, RemoteException { + ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe(); + try { + TransferPipe.dumpAsync(binder, pipe[1].getFileDescriptor(), args); + + // Data is written completely when dumpAsync is done + pipe[1].close(); + pipe[1] = null; + + byte[] buffer = new byte[4096]; + try (ByteArrayOutputStream combinedBuffer = new ByteArrayOutputStream()) { + try (FileInputStream is = new FileInputStream(pipe[0].getFileDescriptor())) { + while (true) { + int numRead = is.read(buffer); + if (numRead == -1) { + break; + } + + combinedBuffer.write(buffer, 0, numRead); + } + } + + return combinedBuffer.toByteArray(); + } + } finally { + pipe[0].close(); + IoUtils.closeQuietly(pipe[1]); + } + } + static void go(Caller caller, IInterface iface, FileDescriptor out, String prefix, String[] args) throws IOException, RemoteException { go(caller, iface, out, prefix, args, DEFAULT_TIMEOUT); diff --git a/core/java/com/android/internal/print/DumpUtils.java b/core/java/com/android/internal/print/DumpUtils.java new file mode 100644 index 000000000000..28c7fc2182b2 --- /dev/null +++ b/core/java/com/android/internal/print/DumpUtils.java @@ -0,0 +1,356 @@ +/* + * Copyright (C) 2017 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.content.ComponentName; +import android.content.ComponentNameProto; +import android.content.Context; +import android.print.PageRange; +import android.print.PrintAttributes; +import android.print.PrintDocumentInfo; +import android.print.PrintJobId; +import android.print.PrintJobInfo; +import android.print.PrinterCapabilitiesInfo; +import android.print.PrinterId; +import android.print.PrinterInfo; +import android.service.print.MarginsProto; +import android.service.print.MediaSizeProto; +import android.service.print.PageRangeProto; +import android.service.print.PrintAttributesProto; +import android.service.print.PrintDocumentInfoProto; +import android.service.print.PrintJobInfoProto; +import android.service.print.PrinterCapabilitiesProto; +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 + */ +public class DumpUtils { + /** + * Write a string to a proto if the string is not {@code null}. + * + * @param proto The proto to write to + * @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) { + if (string != null) { + proto.write(id, string); + } + } + + /** + * Write a {@link ComponentName} to a proto. + * + * @param proto The proto to write to + * @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()); + proto.end(token); + } + + /** + * Write a {@link PrinterId} to a proto. + * + * @param proto The proto to write to + * @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, + @NonNull PrinterId printerId) { + long token = proto.start(id); + writeComponentName(proto, PrinterIdProto.SERVICE_NAME, printerId.getServiceName()); + proto.write(PrinterIdProto.LOCAL_ID, printerId.getLocalId()); + proto.end(token); + } + + /** + * Write a {@link PrinterCapabilitiesInfo} to a proto. + * + * @param proto The proto to write to + * @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()); + + int numMediaSizes = cap.getMediaSizes().size(); + for (int i = 0; i < numMediaSizes; i++) { + writeMediaSize(context, proto, PrinterCapabilitiesProto.MEDIA_SIZES, + cap.getMediaSizes().get(i)); + } + + int numResolutions = cap.getResolutions().size(); + for (int i = 0; i < numResolutions; i++) { + writeResolution(proto, PrinterCapabilitiesProto.RESOLUTIONS, + cap.getResolutions().get(i)); + } + + if ((cap.getColorModes() & PrintAttributes.COLOR_MODE_MONOCHROME) != 0) { + proto.write(PrinterCapabilitiesProto.COLOR_MODES, + PrintAttributesProto.COLOR_MODE_MONOCHROME); + } + if ((cap.getColorModes() & PrintAttributes.COLOR_MODE_COLOR) != 0) { + proto.write(PrinterCapabilitiesProto.COLOR_MODES, + PrintAttributesProto.COLOR_MODE_COLOR); + } + + if ((cap.getDuplexModes() & PrintAttributes.DUPLEX_MODE_NONE) != 0) { + proto.write(PrinterCapabilitiesProto.DUPLEX_MODES, + PrintAttributesProto.DUPLEX_MODE_NONE); + } + if ((cap.getDuplexModes() & PrintAttributes.DUPLEX_MODE_LONG_EDGE) != 0) { + proto.write(PrinterCapabilitiesProto.DUPLEX_MODES, + PrintAttributesProto.DUPLEX_MODE_LONG_EDGE); + } + if ((cap.getDuplexModes() & PrintAttributes.DUPLEX_MODE_SHORT_EDGE) != 0) { + proto.write(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 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()); + + PrinterCapabilitiesInfo cap = info.getCapabilities(); + if (cap != null) { + writePrinterCapabilities(context, proto, PrinterInfoProto.CAPABILITIES, cap); + } + + proto.end(token); + } + + /** + * Write a {@link PrintAttributes.MediaSize} to a proto. + * + * @param context The context used to resolve resources + * @param proto The proto to write to + * @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()); + proto.end(token); + } + + /** + * Write a {@link PrintAttributes.Resolution} to a proto. + * + * @param proto The proto to write to + * @param id The proto-id of the component name + * @param res The resolution to write + */ + public static void writeResolution(@NonNull ProtoOutputStream proto, 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()); + proto.end(token); + } + + /** + * Write a {@link PrintAttributes.Margins} to a proto. + * + * @param proto The proto to write to + * @param id The proto-id of the component name + * @param margins The margins to write + */ + public static void writeMargins(@NonNull ProtoOutputStream proto, 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()); + proto.end(token); + } + + /** + * Write a {@link PrintAttributes} to a proto. + * + * @param context The context used to resolve resources + * @param proto The proto to write to + * @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); + + PrintAttributes.MediaSize mediaSize = attributes.getMediaSize(); + if (mediaSize != null) { + writeMediaSize(context, proto, PrintAttributesProto.MEDIA_SIZE, mediaSize); + } + + proto.write(PrintAttributesProto.IS_PORTRAIT, attributes.isPortrait()); + + PrintAttributes.Resolution res = attributes.getResolution(); + if (res != null) { + writeResolution(proto, PrintAttributesProto.RESOLUTION, res); + } + + PrintAttributes.Margins minMargins = attributes.getMinMargins(); + if (minMargins != null) { + writeMargins(proto, PrintAttributesProto.MIN_MARGINS, minMargins); + } + + proto.write(PrintAttributesProto.COLOR_MODE, attributes.getColorMode()); + proto.write(PrintAttributesProto.DUPLEX_MODE, attributes.getDuplexMode()); + proto.end(token); + } + + /** + * Write a {@link PrintDocumentInfo} to a proto. + * + * @param proto The proto to write to + * @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()); + + int pageCount = info.getPageCount(); + if (pageCount != PrintDocumentInfo.PAGE_COUNT_UNKNOWN) { + proto.write(PrintDocumentInfoProto.PAGE_COUNT, pageCount); + } + + proto.write(PrintDocumentInfoProto.CONTENT_TYPE, info.getContentType()); + proto.write(PrintDocumentInfoProto.DATA_SIZE, info.getDataSize()); + proto.end(token); + } + + /** + * Write a {@link PageRange} to a proto. + * + * @param proto The proto to write to + * @param id The proto-id of the component name + * @param range The range to write + */ + public static void writePageRange(@NonNull ProtoOutputStream proto, long id, + @NonNull PageRange range) { + long token = proto.start(id); + proto.write(PageRangeProto.START, range.getStart()); + proto.write(PageRangeProto.END, range.getEnd()); + proto.end(token); + } + + /** + * Write a {@link PrintJobInfo} to a proto. + * + * @param context The context used to resolve resources + * @param proto The proto to write to + * @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()); + + PrintJobId printJobId = printJobInfo.getId(); + if (printJobId != null) { + proto.write(PrintJobInfoProto.PRINT_JOB_ID, printJobId.flattenToString()); + } + + int state = printJobInfo.getState(); + if (state >= PrintJobInfoProto.STATE_CREATED && state <= PrintJobInfoProto.STATE_CANCELED) { + proto.write(PrintJobInfoProto.STATE, state); + } else { + proto.write(PrintJobInfoProto.STATE, PrintJobInfoProto.STATE_UNKNOWN); + } + + PrinterId printer = printJobInfo.getPrinterId(); + if (printer != null) { + writePrinterId(proto, PrintJobInfoProto.PRINTER, printer); + } + + String tag = printJobInfo.getTag(); + if (tag != null) { + proto.write(PrintJobInfoProto.TAG, tag); + } + + proto.write(PrintJobInfoProto.CREATION_TIME, printJobInfo.getCreationTime()); + + PrintAttributes attributes = printJobInfo.getAttributes(); + if (attributes != null) { + writePrintAttributes(context, proto, PrintJobInfoProto.ATTRIBUTES, attributes); + } + + PrintDocumentInfo docInfo = printJobInfo.getDocumentInfo(); + if (docInfo != null) { + writePrintDocumentInfo(proto, PrintJobInfoProto.DOCUMENT_INFO, docInfo); + } + + proto.write(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]); + } + } + + proto.write(PrintJobInfoProto.HAS_ADVANCED_OPTIONS, + printJobInfo.getAdvancedOptions() != null); + proto.write(PrintJobInfoProto.PROGRESS, printJobInfo.getProgress()); + + CharSequence status = printJobInfo.getStatus(context.getPackageManager()); + if (status != null) { + proto.write(PrintJobInfoProto.STATUS, status.toString()); + } + + proto.end(token); + } +} diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto index e1991146ddb9..5914f5665eb7 100644 --- a/core/proto/android/os/incident.proto +++ b/core/proto/android/os/incident.proto @@ -28,6 +28,7 @@ import "frameworks/base/core/proto/android/service/netstats.proto"; import "frameworks/base/core/proto/android/service/notification.proto"; import "frameworks/base/core/proto/android/service/package.proto"; import "frameworks/base/core/proto/android/service/power.proto"; +import "frameworks/base/core/proto/android/service/print.proto"; import "frameworks/base/core/proto/android/providers/settings.proto"; import "frameworks/base/core/proto/android/os/kernelwake.proto"; @@ -66,4 +67,5 @@ message IncidentProto { android.service.notification.NotificationServiceDumpProto notification = 3004; android.service.pm.PackageServiceDumpProto package = 3008; android.service.power.PowerServiceDumpProto power = 3009; + android.service.print.PrintServiceDumpProto print = 3010; } diff --git a/core/proto/android/service/print.proto b/core/proto/android/service/print.proto new file mode 100644 index 000000000000..f09987248d58 --- /dev/null +++ b/core/proto/android/service/print.proto @@ -0,0 +1,368 @@ +/* + * Copyright (C) 2017 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. + */ + +syntax = "proto3"; + +package android.service.print; + +option java_multiple_files = true; +option java_outer_classname = "PrintServiceProto"; + +import "frameworks/base/core/proto/android/content/component_name.proto"; + +message PrintServiceDumpProto { + // Each user has a separate printer state + repeated PrintUserStateProto userStates = 1; +} + +message PrintUserStateProto { + // Should be 0, 10, 11, 12, etc. where 0 is the owner. + int32 user_id = 1; + + // The installed print services + repeated InstalledPrintServiceProto installed_services = 2; + + // The disabled print services + repeated android.content.ComponentNameProto disabled_services = 3; + + // The active print services + repeated ActivePrintServiceProto active_services = 4; + + // The cached print jobs + repeated CachedPrintJobProto cached_print_jobs = 5; + + // The printer discovery sessions + repeated PrinterDiscoverySessionProto discovery_sessions = 6; + + // The print spooler state + PrintSpoolerStateProto print_spooler_state = 7; +} + +message PrintSpoolerStateProto { + // Is the print spooler destroyed? + bool is_destroyed = 1; + + // Is the print spooler bound? + bool is_bound = 2; + + // State internal to the print spooler + PrintSpoolerInternalStateProto internal_state = 3; +} + +message PrintSpoolerInternalStateProto { + // Print jobs + repeated PrintJobInfoProto print_jobs = 1; + + // Files used by these print jobs + repeated string print_job_files = 2; + + // Approved print services + repeated android.content.ComponentNameProto approved_services = 3; +} + +message PrinterCapabilitiesProto { + // Minimum margins of the printer + MarginsProto min_margins = 1; + + // List of supported media sizes + repeated MediaSizeProto media_sizes = 2; + + // List of supported resolutions + repeated ResolutionProto resolutions = 3; + + // List of supported color modes + repeated PrintAttributesProto.ColorMode color_modes = 4; + + // List of supported duplex modes + repeated PrintAttributesProto.DuplexMode duplex_modes = 5; +} + +message PrinterInfoProto { + // The id of the printer + PrinterIdProto id = 1; + + // The name of the printer + string name = 2; + + enum Status { + // unused + __STATUS_UNUSED = 0; + + // Printer is idle + STATUS_IDLE = 1; + + // Printer is busy + STATUS_BUSY = 2; + + // Printer is unavailable + STATUS_UNAVAILABLE = 3; + } + // The status of the printer + Status status = 3; + + // The description of the printer + string description = 4; + + // The capabilities of the printer + PrinterCapabilitiesProto capabilities = 5; +} + +message PrinterDiscoverySessionProto { + // Is this session destroyed? + bool is_destroyed = 1; + + // Is printer discovery in progress? + bool is_printer_discovery_in_progress = 2; + + // List of printer discovery observers + repeated string printer_discovery_observers = 3; + + // List of discovery request + repeated string discovery_requests = 4; + + // List of ids of printers that are have tracking requests + repeated PrinterIdProto tracked_printer_requests = 5; + + // List of printers found + repeated PrinterInfoProto printer = 6; +} + +message InstalledPrintServiceProto { + // Component name of the service + android.content.ComponentNameProto component_name = 1; + + // Settings activity for this service + string settings_activity = 2; + + // Add printers activity for this service + string add_printers_activity = 3; + + // Advances options activity for this service + string advanced_options_activity = 4; +} + +message PrinterIdProto { + // Component name of the service that reported the printer + android.content.ComponentNameProto service_name = 1; + + // Local id of the printer + string local_id = 2; +} + +message ActivePrintServiceProto { + // Component name of the service + android.content.ComponentNameProto component_name = 1; + + // Is the active service destroyed + bool is_destroyed = 2; + + // Is the active service bound + bool is_bound = 3; + + // Has the active service a discovery session + bool has_discovery_session = 4; + + // Has the active service a active print jobs + bool has_active_print_jobs = 5; + + // Is the active service discovering printers + bool is_discovering_printers = 6; + + // The tracked printers of this active service + repeated PrinterIdProto tracked_printers = 7; +} + +message MediaSizeProto { + // Id of this media size + string id = 1; + + // Label of this media size + string label = 2; + + // Height of the media + int32 height_mils = 3; + + // Width of the media + int32 width_mils = 4; +} + +message ResolutionProto { + // Id of this resolution + string id = 1; + + // Label for this resoltion + string label = 2; + + // Resolution in horizontal orientation + int32 horizontal_dpi = 3; + + // Resolution in vertical orientation + int32 vertical_dpi = 4; +} + +message MarginsProto { + // Space at the top + int32 top_mils = 1; + + // Space at the left + int32 left_mils = 2; + + // Space at the right + int32 right_mils = 3; + + // Space at the bottom + int32 bottom_mils = 4; +} + +message PrintAttributesProto { + // Media to use + ResolutionProto media_size = 1; + + // Is the media in portrait mode? + bool is_portrait = 2; + + // Resolution to use + ResolutionProto resolution = 3; + + // Margins around the document + MarginsProto min_margins = 4; + + enum ColorMode { + // unused + __COLOR_MODE_UNUSED = 0; + + // Use black, white, gray + COLOR_MODE_MONOCHROME = 1; + + // Use full color is available + COLOR_MODE_COLOR = 2; + } + // Color mode to use + ColorMode color_mode = 5; + + enum DuplexMode { + // unused + __DUPLEX_MODE_UNUSED = 0; + + // No duplex + DUPLEX_MODE_NONE = 1; + + // Duplex where the long edge attached + DUPLEX_MODE_LONG_EDGE = 2; + + // Duplex where the short edge attach + DUPLEX_MODE_SHORT_EDGE = 4; + } + // Duplex mode to use + DuplexMode duplex_mode = 6; +} + +message PrintDocumentInfoProto { + // Name of the document to print + string name = 1; + + // Number of pages in the doc + int32 page_count = 2; + + // Type of content (see PrintDocumentInfo.ContentType) + int32 content_type = 3; + + // The size of the the document + int64 data_size = 4; +} + +message PageRangeProto { + // Start of the range + int32 start = 1; + + // End of the range (included) + int32 end = 2; +} + +message PrintJobInfoProto { + // Label of the job + string label = 1; + + // Id of the job + string print_job_id = 2; + + enum State { + // Unknown state + STATE_UNKNOWN = 0; + + // The print job is being created but not yet ready to be printed + STATE_CREATED = 1; + + // The print jobs is created, it is ready to be printed and should be processed + STATE_QUEUED = 2; + + // The print job is being printed + STATE_STARTED = 3; + + // The print job is blocked + STATE_BLOCKED = 4; + + // The print job is successfully printed + STATE_COMPLETED = 5; + + // The print job was printing but printing failed + STATE_FAILED = 6; + + // The print job is canceled + STATE_CANCELED = 7; + } + + // State of the job + State state = 3; + + // Printer handling the job + PrinterIdProto printer = 4; + + // Tag assigned to the job + string tag = 5; + + // Time the job was created + int64 creation_time = 6; + + // Attributes of the job + PrintAttributesProto attributes = 7; + + // Document info of the job + PrintDocumentInfoProto document_info = 8; + + // If the job current getting canceled + bool is_canceling = 9; + + // The selected ranges of the job + repeated PageRangeProto pages = 10; + + // Does the job have any advanced options + bool has_advanced_options = 11; + + // Progress of the job + float progress = 12; + + // The current service set state + string status = 13; +} + +message CachedPrintJobProto { + // The id of the app the job belongs to + int32 app_id = 1; + + // The print job + PrintJobInfoProto print_job = 2; +}
\ No newline at end of file diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java index d15ae1c07ca7..e0a3f6cb31ca 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java +++ b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java @@ -16,6 +16,9 @@ package com.android.printspooler.model; +import static com.android.internal.print.DumpUtils.writeComponentName; +import static com.android.internal.print.DumpUtils.writePrintJobInfo; + import android.annotation.FloatRange; import android.annotation.NonNull; import android.annotation.Nullable; @@ -26,6 +29,7 @@ import android.content.Context; import android.content.Intent; import android.graphics.drawable.Icon; import android.os.AsyncTask; +import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import android.os.Message; @@ -44,16 +48,19 @@ import android.print.PrintJobId; import android.print.PrintJobInfo; import android.print.PrintManager; import android.print.PrinterId; +import android.service.print.PrintSpoolerInternalStateProto; import android.text.TextUtils; import android.util.ArrayMap; import android.util.AtomicFile; import android.util.Log; import android.util.Slog; import android.util.Xml; +import android.util.proto.ProtoOutputStream; import com.android.internal.logging.MetricsLogger; import com.android.internal.os.HandlerCaller; import com.android.internal.util.FastXmlSerializer; +import com.android.internal.util.Preconditions; import com.android.printspooler.R; import com.android.printspooler.util.ApprovedPrintServices; @@ -152,29 +159,26 @@ public final class PrintSpoolerService extends Service { return new PrintSpooler(); } - @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + private void dumpLocked(PrintWriter pw, String[] args) { String prefix = (args.length > 0) ? args[0] : ""; String tab = " "; - synchronized (mLock) { - 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 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("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(); } } } @@ -188,6 +192,68 @@ public final class PrintSpoolerService extends Service { } } + private void dumpLocked(@NonNull ProtoOutputStream proto) { + int numPrintJobs = mPrintJobs.size(); + for (int i = 0; i < numPrintJobs; i++) { + writePrintJobInfo(this, proto, PrintSpoolerInternalStateProto.PRINT_JOBS, + mPrintJobs.get(i)); + } + + File[] files = getFilesDir().listFiles(); + if (files != null) { + 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()); + } + } + } + + Set<String> approvedPrintServices = (new ApprovedPrintServices(this)).getApprovedServices(); + if (approvedPrintServices != null) { + for (String approvedService : approvedPrintServices) { + ComponentName componentName = ComponentName.unflattenFromString(approvedService); + if (componentName != null) { + writeComponentName(proto, PrintSpoolerInternalStateProto.APPROVED_SERVICES, + componentName); + } + } + } + + proto.flush(); + } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + fd = Preconditions.checkNotNull(fd); + + int opti = 0; + boolean dumpAsProto = false; + while (opti < args.length) { + String opt = args[opti]; + if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') { + break; + } + opti++; + if ("--proto".equals(opt)) { + dumpAsProto = true; + } + } + + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + if (dumpAsProto) { + dumpLocked(new ProtoOutputStream(fd)); + } else { + dumpLocked(pw, args); + } + } + } finally { + Binder.restoreCallingIdentity(identity); + } + } + private void sendOnPrintJobQueued(PrintJobInfo printJob) { Message message = mHandlerCaller.obtainMessageO( HandlerCallerCallback.MSG_ON_PRINT_JOB_QUEUED, printJob); @@ -752,7 +818,7 @@ public final class PrintSpoolerService extends Service { * * @param printerId the id of the printer the icon belongs to * @param icon the icon that was loaded - * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon() + * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon */ public void onCustomPrinterIconLoaded(PrinterId printerId, Icon icon) { mCustomIconCache.onCustomPrinterIconLoaded(printerId, icon); @@ -765,7 +831,7 @@ public final class PrintSpoolerService extends Service { * @param printerId the id of the printer the icon should be loaded for * @return the custom icon to be used for the printer or null if the icon is * not yet available - * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon() + * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon */ public Icon getCustomPrinterIcon(PrinterId printerId) { return mCustomIconCache.getIcon(printerId); diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java index 6c417a9baf93..33d1fed4ef56 100644 --- a/services/print/java/com/android/server/print/PrintManagerService.java +++ b/services/print/java/com/android/server/print/PrintManagerService.java @@ -50,8 +50,10 @@ import android.printservice.PrintServiceInfo; import android.printservice.recommendation.IRecommendationsChangeListener; import android.printservice.recommendation.RecommendationInfo; import android.provider.Settings; +import android.service.print.PrintServiceDumpProto; import android.util.Log; import android.util.SparseArray; +import android.util.proto.ProtoOutputStream; import com.android.internal.content.PackageMonitor; import com.android.internal.os.BackgroundThread; @@ -638,19 +640,32 @@ public final class PrintManagerService extends SystemService { @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { fd = Preconditions.checkNotNull(fd); - pw = Preconditions.checkNotNull(pw); if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return; + int opti = 0; + boolean dumpAsProto = false; + int user = UserHandle.USER_ALL; + while (opti < args.length) { + String opt = args[opti]; + if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') { + break; + } + opti++; + if ("--proto".equals(opt)) { + dumpAsProto = true; + } else { + pw.println("Unknown argument: " + opt + "; use -h for help"); + } + } + synchronized (mLock) { final long identity = Binder.clearCallingIdentity(); try { - pw.println("PRINT MANAGER STATE (dumpsys print)"); - final int userStateCount = mUserStates.size(); - for (int i = 0; i < userStateCount; i++) { - UserState userState = mUserStates.valueAt(i); - userState.dump(fd, pw, ""); - pw.println(); + if (dumpAsProto) { + dumpLocked(new ProtoOutputStream(fd), UserHandle.of(user)); + } else { + dumpLocked(fd, pw, UserHandle.of(user)); } } finally { Binder.restoreCallingIdentity(identity); @@ -658,6 +673,37 @@ public final class PrintManagerService extends SystemService { } } + private void dumpLocked(@NonNull ProtoOutputStream proto, @NonNull UserHandle user) { + final int userStateCount = mUserStates.size(); + for (int i = 0; i < userStateCount; i++) { + UserState userState = mUserStates.valueAt(i); + + if (user.equals(UserHandle.ALL) || mUserStates.keyAt(i) == user.getIdentifier()) { + long token = proto.start(PrintServiceDumpProto.USER_STATES); + userState.dump(proto); + proto.end(token); + } + } + + proto.flush(); + } + + private void dumpLocked(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, + @NonNull UserHandle user) { + pw = Preconditions.checkNotNull(pw); + + pw.println("PRINT MANAGER STATE (dumpsys print)"); + final int userStateCount = mUserStates.size(); + for (int i = 0; i < userStateCount; i++) { + UserState userState = mUserStates.valueAt(i); + + if (user.equals(UserHandle.ALL) || mUserStates.keyAt(i) == user.getIdentifier()) { + userState.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 fb78457538be..13462cd3e3e4 100644 --- a/services/print/java/com/android/server/print/RemotePrintService.java +++ b/services/print/java/com/android/server/print/RemotePrintService.java @@ -16,6 +16,9 @@ package com.android.server.print; +import static com.android.internal.print.DumpUtils.writeComponentName; +import static com.android.internal.print.DumpUtils.writePrinterId; + import android.annotation.FloatRange; import android.annotation.NonNull; import android.annotation.Nullable; @@ -42,7 +45,11 @@ import android.print.PrinterId; import android.print.PrinterInfo; import android.printservice.IPrintService; 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 java.io.PrintWriter; import java.lang.ref.WeakReference; @@ -60,6 +67,8 @@ final class RemotePrintService implements DeathRecipient { private static final boolean DEBUG = false; + private final Object mLock = new Object(); + private final Context mContext; private final ComponentName mComponentName; @@ -94,6 +103,7 @@ final class RemotePrintService implements DeathRecipient { private List<PrinterId> mDiscoveryPriorityList; + @GuardedBy("mLock") private List<PrinterId> mTrackedPrinterList; public static interface PrintServiceCallbacks { @@ -443,11 +453,14 @@ final class RemotePrintService implements DeathRecipient { } private void handleStartPrinterStateTracking(final @NonNull PrinterId printerId) { - // Take a note we are tracking the printer. - if (mTrackedPrinterList == null) { - mTrackedPrinterList = new ArrayList<PrinterId>(); + synchronized (mLock) { + // Take a note we are tracking the printer. + if (mTrackedPrinterList == null) { + mTrackedPrinterList = new ArrayList<PrinterId>(); + } + mTrackedPrinterList.add(printerId); } - mTrackedPrinterList.add(printerId); + if (!isBound()) { ensureBound(); mPendingCommands.add(new Runnable() { @@ -474,13 +487,16 @@ final class RemotePrintService implements DeathRecipient { } private void handleStopPrinterStateTracking(final PrinterId printerId) { - // We are no longer tracking the printer. - if (mTrackedPrinterList == null || !mTrackedPrinterList.remove(printerId)) { - return; - } - if (mTrackedPrinterList.isEmpty()) { - mTrackedPrinterList = null; + synchronized (mLock) { + // We are no longer tracking the printer. + if (mTrackedPrinterList == null || !mTrackedPrinterList.remove(printerId)) { + return; + } + if (mTrackedPrinterList.isEmpty()) { + mTrackedPrinterList = null; + } } + if (!isBound()) { ensureBound(); mPendingCommands.add(new Runnable() { @@ -502,14 +518,37 @@ final class RemotePrintService implements DeathRecipient { } private void stopTrackingAllPrinters() { - if (mTrackedPrinterList == null) { - return; + synchronized (mLock) { + if (mTrackedPrinterList == null) { + return; + } + final int trackedPrinterCount = mTrackedPrinterList.size(); + for (int i = trackedPrinterCount - 1; i >= 0; i--) { + PrinterId printerId = mTrackedPrinterList.get(i); + if (printerId.getServiceName().equals(mComponentName)) { + handleStopPrinterStateTracking(printerId); + } + } } - final int trackedPrinterCount = mTrackedPrinterList.size(); - for (int i = trackedPrinterCount - 1; i >= 0; i--) { - PrinterId printerId = mTrackedPrinterList.get(i); - if (printerId.getServiceName().equals(mComponentName)) { - handleStopPrinterStateTracking(printerId); + } + + public void dump(@NonNull ProtoOutputStream proto) { + writeComponentName(proto, 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, + 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)); + } } } } @@ -529,8 +568,11 @@ final class RemotePrintService implements DeathRecipient { .append(String.valueOf(mHasActivePrintJobs)).println(); pw.append(prefix).append(tab).append("isDiscoveringPrinters=") .append(String.valueOf(mDiscoveryPriorityList != null)).println(); - pw.append(prefix).append(tab).append("trackedPrinters=") - .append((mTrackedPrinterList != null) ? mTrackedPrinterList.toString() : "null"); + + synchronized (mLock) { + pw.append(prefix).append(tab).append("trackedPrinters=").append( + (mTrackedPrinterList != null) ? mTrackedPrinterList.toString() : "null"); + } } private boolean isBound() { @@ -574,7 +616,11 @@ final class RemotePrintService implements DeathRecipient { mHasActivePrintJobs = false; mHasPrinterDiscoverySession = false; mDiscoveryPriorityList = null; - mTrackedPrinterList = null; + + synchronized (mLock) { + mTrackedPrinterList = null; + } + if (isBound()) { try { mPrintService.setClient(null); @@ -617,11 +663,13 @@ final class RemotePrintService implements DeathRecipient { if (mServiceDied && mDiscoveryPriorityList != null) { handleStartPrinterDiscovery(mDiscoveryPriorityList); } - // If the service died and printers were tracked, start tracking. - if (mServiceDied && mTrackedPrinterList != null) { - final int trackedPrinterCount = mTrackedPrinterList.size(); - for (int i = 0; i < trackedPrinterCount; i++) { - handleStartPrinterStateTracking(mTrackedPrinterList.get(i)); + synchronized (mLock) { + // If the service died and printers were tracked, start tracking. + if (mServiceDied && mTrackedPrinterList != null) { + final int trackedPrinterCount = mTrackedPrinterList.size(); + for (int i = 0; i < trackedPrinterCount; i++) { + handleStartPrinterStateTracking(mTrackedPrinterList.get(i)); + } } } // Finally, do all the pending work. diff --git a/services/print/java/com/android/server/print/RemotePrintSpooler.java b/services/print/java/com/android/server/print/RemotePrintSpooler.java index abd2244959cf..f654fcb60750 100644 --- a/services/print/java/com/android/server/print/RemotePrintSpooler.java +++ b/services/print/java/com/android/server/print/RemotePrintSpooler.java @@ -40,8 +40,10 @@ import android.print.PrintJobInfo; import android.print.PrintManager; import android.print.PrinterId; import android.printservice.PrintService; +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; @@ -363,7 +365,7 @@ final class RemotePrintSpooler { * * @param printerId the id of the printer the icon belongs to * @param icon the icon that was loaded - * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon() + * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon */ public final void onCustomPrinterIconLoaded(@NonNull PrinterId printerId, @Nullable Icon icon) { @@ -396,7 +398,7 @@ final class RemotePrintSpooler { * @param printerId the id of the printer the icon should be loaded for * @return the custom icon to be used for the printer or null if the icon is * not yet available - * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon() + * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon */ public final @Nullable Icon getCustomPrinterIcon(@NonNull PrinterId printerId) { throwIfCalledOnMainThread(); @@ -556,6 +558,20 @@ final class RemotePrintSpooler { } } + public void dump(@NonNull ProtoOutputStream proto) { + synchronized (mLock) { + proto.write(PrintSpoolerStateProto.IS_DESTROYED, mDestroyed); + proto.write(PrintSpoolerStateProto.IS_BOUND, mRemoteInstance != null); + } + + try { + proto.write(PrintSpoolerStateProto.INTERNAL_STATE, + TransferPipe.dumpAsync(getRemoteInstanceLazy().asBinder(), "--proto")); + } 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=") diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java index 5770c5079d94..58833bee1b98 100644 --- a/services/print/java/com/android/server/print/UserState.java +++ b/services/print/java/com/android/server/print/UserState.java @@ -20,6 +20,12 @@ import static android.content.pm.PackageManager.GET_META_DATA; import static android.content.pm.PackageManager.GET_SERVICES; import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING; +import static com.android.internal.print.DumpUtils.writeComponentName; +import static com.android.internal.print.DumpUtils.writePrintJobInfo; +import static com.android.internal.print.DumpUtils.writePrinterId; +import static com.android.internal.print.DumpUtils.writePrinterInfo; +import static com.android.internal.print.DumpUtils.writeStringIfNotNull; + import android.annotation.NonNull; import android.annotation.Nullable; import android.app.PendingIntent; @@ -58,6 +64,10 @@ import android.printservice.recommendation.IRecommendationsChangeListener; import android.printservice.recommendation.RecommendationInfo; import android.provider.DocumentsContract; import android.provider.Settings; +import android.service.print.CachedPrintJobProto; +import android.service.print.InstalledPrintServiceProto; +import android.service.print.PrintUserStateProto; +import android.service.print.PrinterDiscoverySessionProto; import android.text.TextUtils; import android.text.TextUtils.SimpleStringSplitter; import android.util.ArrayMap; @@ -65,6 +75,7 @@ import android.util.ArraySet; 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; @@ -803,55 +814,107 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks, mDestroyed = true; } + public void dump(@NonNull ProtoOutputStream proto) { + synchronized (mLock) { + proto.write(PrintUserStateProto.USER_ID, mUserId); + + final int installedServiceCount = mInstalledServices.size(); + for (int i = 0; i < installedServiceCount; i++) { + long token = proto.start(PrintUserStateProto.INSTALLED_SERVICES); + PrintServiceInfo installedService = mInstalledServices.get(i); + + ResolveInfo resolveInfo = installedService.getResolveInfo(); + writeComponentName(proto, InstalledPrintServiceProto.COMPONENT_NAME, + new ComponentName(resolveInfo.serviceInfo.packageName, + resolveInfo.serviceInfo.name)); + + writeStringIfNotNull(proto, InstalledPrintServiceProto.SETTINGS_ACTIVITY, + installedService.getSettingsActivityName()); + writeStringIfNotNull(proto, InstalledPrintServiceProto.ADD_PRINTERS_ACTIVITY, + installedService.getAddPrintersActivityName()); + writeStringIfNotNull(proto, InstalledPrintServiceProto.ADVANCED_OPTIONS_ACTIVITY, + installedService.getAdvancedOptionsActivityName()); + + proto.end(token); + } + + for (ComponentName disabledService : mDisabledServices) { + writeComponentName(proto, PrintUserStateProto.DISABLED_SERVICES, disabledService); + } + + final int activeServiceCount = mActiveServices.size(); + for (int i = 0; i < activeServiceCount; i++) { + long token = proto.start(PrintUserStateProto.ACTIVE_SERVICES); + mActiveServices.valueAt(i).dump(proto); + proto.end(token); + } + + mPrintJobForAppCache.dumpLocked(proto); + + if (mPrinterDiscoverySession != null) { + long token = proto.start(PrintUserStateProto.DISCOVERY_SESSIONS); + mPrinterDiscoverySession.dumpLocked(proto); + proto.end(token); + } + + } + + long token = proto.start(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 = " "; - 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(); - } + 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("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.dump(pw, prefix + tab + tab); + 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.dump(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(); @@ -1611,7 +1674,40 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks, } } - public void dump(PrintWriter pw, String prefix) { + public void dumpLocked(@NonNull ProtoOutputStream proto) { + proto.write(PrinterDiscoverySessionProto.IS_DESTROYED, mDestroyed); + proto.write(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, + observer.toString()); + } + mDiscoveryObservers.finishBroadcast(); + + 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()); + } + + final int trackedPrinters = mStateTrackedPrinters.size(); + for (int i = 0; i < trackedPrinters; i++) { + PrinterId printer = mStateTrackedPrinters.get(i); + writePrinterId(proto, 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(); @@ -1989,19 +2085,36 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks, } } - public void dump(PrintWriter pw, String prefix) { - synchronized (mLock) { - 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(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) { + 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); + + proto.write(CachedPrintJobProto.APP_ID, appId); + + writePrintJobInfo(mContext, proto, CachedPrintJobProto.PRINT_JOB, + bucket.get(j)); + + proto.end(token); } } } |