summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/print/PrintAttributes.java11
-rw-r--r--core/java/android/print/PrintJobInfo.java15
-rw-r--r--core/java/android/print/PrinterInfo.java7
-rw-r--r--core/java/com/android/internal/os/TransferPipe.java56
-rw-r--r--core/java/com/android/internal/print/DumpUtils.java356
-rw-r--r--core/proto/android/os/incident.proto2
-rw-r--r--core/proto/android/service/print.proto368
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java108
-rw-r--r--services/print/java/com/android/server/print/PrintManagerService.java60
-rw-r--r--services/print/java/com/android/server/print/RemotePrintService.java98
-rw-r--r--services/print/java/com/android/server/print/RemotePrintSpooler.java20
-rw-r--r--services/print/java/com/android/server/print/UserState.java221
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);
}
}
}