Merge "Handle print serivce crashes." into klp-dev
diff --git a/core/java/android/print/PrintDocumentAdapter.java b/core/java/android/print/PrintDocumentAdapter.java
index c81ca95..8ac34c1 100644
--- a/core/java/android/print/PrintDocumentAdapter.java
+++ b/core/java/android/print/PrintDocumentAdapter.java
@@ -20,8 +20,6 @@
 import android.os.CancellationSignal;
 import android.os.ParcelFileDescriptor;
 
-import java.util.List;
-
 /**
  * Base class that provides the content of a document to be printed.
  *
diff --git a/core/java/android/printservice/PrintService.java b/core/java/android/printservice/PrintService.java
index 0ffc40a..012e76ab 100644
--- a/core/java/android/printservice/PrintService.java
+++ b/core/java/android/printservice/PrintService.java
@@ -20,7 +20,6 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
diff --git a/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java b/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java
index 7d6ca56..e47bf0c 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java
@@ -57,7 +57,7 @@
 public class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
     private static final String LOG_TAG = "FusedPrintersProvider";
 
-    private static final boolean DEBUG = true && Build.IS_DEBUGGABLE;
+    private static final boolean DEBUG = false;
 
     private static final double WEIGHT_DECAY_COEFFICIENT = 0.95f;
 
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
index 7266af8..76e548a 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
@@ -73,9 +73,9 @@
 
     private static final String LOG_TAG = "PrintSpoolerService";
 
-    private static final boolean DEBUG_PRINT_JOB_LIFECYCLE = true;
+    private static final boolean DEBUG_PRINT_JOB_LIFECYCLE = false;
 
-    private static final boolean DEBUG_PERSISTENCE = true;
+    private static final boolean DEBUG_PERSISTENCE = false;
 
     private static final boolean PERSISTNECE_MANAGER_ENABLED = true;
 
@@ -838,18 +838,8 @@
                                     resolution.getHorizontalDpi()));
                             serializer.attribute(null, ATTR_VERTICAL_DPI, String.valueOf(
                                     resolution.getVerticalDpi()));
-                            // We prefer to store only the package name and
-                            // resource id and fallback to the label.
-                            if (!TextUtils.isEmpty(mediaSize.mPackageName)
-                                    && resolution.mLabelResId > 0) {
-                                serializer.attribute(null, ATTR_PACKAGE_NAME,
-                                        resolution.mPackageName);
-                                serializer.attribute(null, ATTR_LABEL_RES_ID,
-                                        String.valueOf(resolution.mLabelResId));
-                            } else {
-                                serializer.attribute(null, ATTR_LABEL,
-                                        resolution.getLabel(getPackageManager()));
-                            }
+                            serializer.attribute(null, ATTR_LABEL,
+                                    resolution.getLabel(getPackageManager()));
                             serializer.endTag(null, TAG_RESOLUTION);
                         }
 
@@ -1047,11 +1037,7 @@
                             ATTR_HORIZONTAL_DPI));
                     final int verticalDpi = Integer.parseInt(parser.getAttributeValue(null,
                             ATTR_VERTICAL_DPI));
-                    String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
-                    final int labelResId = Integer.parseInt(
-                            parser.getAttributeValue(null, ATTR_LABEL_RES_ID));
-                    Resolution resolution = new Resolution(id, label, packageName, labelResId,
-                                horizontalDpi, verticalDpi);
+                    Resolution resolution = new Resolution(id, label, horizontalDpi, verticalDpi);
                     builder.setResolution(resolution);
                     parser.next();
                     skipEmptyTextTags(parser);
diff --git a/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java
index 4006a5a..fd14af9 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java
@@ -17,7 +17,6 @@
 package com.android.printspooler;
 
 import android.os.AsyncTask;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
@@ -43,7 +42,7 @@
 final class RemotePrintDocumentAdapter {
     private static final String LOG_TAG = "RemotePrintDocumentAdapter";
 
-    private static final boolean DEBUG = true && Build.IS_DEBUGGABLE;
+    private static final boolean DEBUG = false;
 
     private final IPrintDocumentAdapter mRemoteInterface;
 
diff --git a/services/java/com/android/server/print/RemotePrintService.java b/services/java/com/android/server/print/RemotePrintService.java
index ddff0ae..0d539b0 100644
--- a/services/java/com/android/server/print/RemotePrintService.java
+++ b/services/java/com/android/server/print/RemotePrintService.java
@@ -21,11 +21,9 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.os.Binder;
-import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.IBinder.DeathRecipient;
-import android.os.AsyncTask;
 import android.os.Looper;
 import android.os.Message;
 import android.os.ParcelFileDescriptor;
@@ -39,8 +37,6 @@
 import android.printservice.IPrintServiceClient;
 import android.util.Slog;
 
-import com.android.internal.R;
-
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -55,7 +51,7 @@
 
     private static final String LOG_TAG = "RemotePrintService";
 
-    private static final boolean DEBUG = true && Build.IS_DEBUGGABLE;
+    private static final boolean DEBUG = false;
 
     private final Context mContext;
 
@@ -65,7 +61,7 @@
 
     private final RemotePrintSpooler mSpooler;
 
-    private final UserState mUserState;
+    private final PrintServiceCallbacks mCallbacks;
 
     private final int mUserId;
 
@@ -83,14 +79,24 @@
 
     private boolean mDestroyed;
 
-    private boolean mAllPrintJobsHandled;
+    private boolean mHasActivePrintJobs;
 
     private boolean mHasPrinterDiscoverySession;
 
+    private List<PrinterId> mDiscoveryPriorityList;
+
+    private List<PrinterId> mTrackedPrinterList;
+
+    public static interface PrintServiceCallbacks {
+        public void onPrintersAdded(List<PrinterInfo> printers);
+        public void onPrintersRemoved(List<PrinterId> printerIds);
+        public void onServiceDied(RemotePrintService service);
+    }
+
     public RemotePrintService(Context context, ComponentName componentName, int userId,
-            RemotePrintSpooler spooler, UserState userState) {
+            RemotePrintSpooler spooler, PrintServiceCallbacks callbacks) {
         mContext = context;
-        mUserState = userState;
+        mCallbacks = callbacks;
         mComponentName = componentName;
         mIntent = new Intent().setComponent(mComponentName);
         mUserId = userId;
@@ -99,15 +105,42 @@
         mPrintServiceClient = new RemotePrintServiceClient(this);
     }
 
+    public ComponentName getComponentName() {
+        return mComponentName;
+    }
+
     public void destroy() {
         mHandler.sendEmptyMessage(MyHandler.MSG_DESTROY);
     }
 
     private void handleDestroy() {
         throwIfDestroyed();
+
+        // Stop tracking printers.
+        if (mTrackedPrinterList != null) {
+            final int trackedPrinterCount = mTrackedPrinterList.size();
+            for (int i = 0; i < trackedPrinterCount; i++) {
+                PrinterId printerId = mTrackedPrinterList.get(i);
+                if (printerId.getServiceName().equals(mComponentName)) {
+                    handleStopPrinterStateTracking(printerId);
+                }
+            }
+        }
+
+        // Stop printer discovery.
+        if (mDiscoveryPriorityList != null) {
+            handleStopPrinterDiscovery();
+        }
+
+        // Destroy the discovery session.
+        if (mHasPrinterDiscoverySession) {
+            handleDestroyPrinterDiscoverySession();
+        }
+
+        // Unbind.
         ensureUnbound();
-        mAllPrintJobsHandled = false;
-        mHasPrinterDiscoverySession = false;
+
+        // Done
         mDestroyed = true;
     }
 
@@ -121,21 +154,9 @@
     }
 
     private void handleBinderDied() {
-        mAllPrintJobsHandled = false;
-        mHasPrinterDiscoverySession = false;
-        mPendingCommands.clear();
-        ensureUnbound();
-
-        // Makes sure all active print jobs are failed since the service
-        // just died. Do this off the main thread since we do to allow
-        // calls into the spooler on the main thread.
-        new AsyncTask<Void, Void, Void>() {
-            @Override
-            protected Void doInBackground(Void... params) {
-                failAllActivePrintJobs();
-                return null;
-            }
-        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
+        mPrintService.asBinder().unlinkToDeath(this, 0);
+        mPrintService = null;
+        mCallbacks.onServiceDied(this);
     }
 
     public void dump(PrintWriter pw, String prefix) {
@@ -148,32 +169,17 @@
         pw.append(prefix).append(tab).append("bound=")
                 .append(String.valueOf(isBound())).println();
         pw.append(prefix).append(tab).append("hasDicoverySession=")
-                .append(String.valueOf(mHasPrinterDiscoverySession));
-    }
-
-    private void failAllActivePrintJobs() {
-        List<PrintJobInfo> printJobs = mSpooler.getPrintJobInfos(mComponentName,
-                PrintJobInfo.STATE_ANY_ACTIVE, PrintManager.APP_ID_ANY);
-        if (printJobs == null) {
-            return;
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            final int printJobCount = printJobs.size();
-            for (int i = 0; i < printJobCount; i++) {
-                PrintJobInfo printJob = printJobs.get(i);
-                mSpooler.setPrintJobState(printJob.getId(), PrintJobInfo.STATE_FAILED,
-                        mContext.getString(R.string.reason_unknown));
-            }
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
+                .append(String.valueOf(mHasPrinterDiscoverySession)).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");
     }
 
     private void handleOnAllPrintJobsHandled() {
         throwIfDestroyed();
 
-        mAllPrintJobsHandled = true;
+        mHasActivePrintJobs = false;
 
         if (isBound()) {
             if (DEBUG) {
@@ -217,7 +223,7 @@
     private void handleOnPrintJobQueued(final PrintJobInfo printJob) {
         throwIfDestroyed();
 
-        mAllPrintJobsHandled = false;
+        mHasActivePrintJobs = true;
 
         if (!isBound()) {
             ensureBound();
@@ -296,7 +302,7 @@
 
             // If the service has no print jobs and no active discovery
             // session anymore we should disconnect from it.
-            if (mAllPrintJobsHandled) {
+            if (!mHasActivePrintJobs) {
                 ensureUnbound();
             }
         }
@@ -326,6 +332,11 @@
             } catch (RemoteException re) {
                 Slog.e(LOG_TAG, "Error starting printer dicovery.", re);
             }
+            // Take a note that we are doing discovery.
+            mDiscoveryPriorityList = new ArrayList<PrinterId>();
+            if (priorityList != null) {
+                mDiscoveryPriorityList.addAll(priorityList);
+            }
         }
     }
 
@@ -347,6 +358,8 @@
             if (DEBUG) {
                 Slog.i(LOG_TAG, "[user: " + mUserId + "] stopPrinterDiscovery()");
             }
+            // We are not doing discovery anymore.
+            mDiscoveryPriorityList = null;
             try {
                 mPrintService.stopPrinterDiscovery();
             } catch (RemoteException re) {
@@ -406,6 +419,11 @@
             } catch (RemoteException re) {
                 Slog.e(LOG_TAG, "Error requesting start printer tracking.", re);
             }
+            // Take a note we are tracking the printer.
+            if (mTrackedPrinterList == null) {
+                mTrackedPrinterList = new ArrayList<PrinterId>();
+            }
+            mTrackedPrinterList.add(printerId);
         }
     }
 
@@ -428,6 +446,11 @@
             if (DEBUG) {
                 Slog.i(LOG_TAG, "[user: " + mUserId + "] stopPrinterTracking()");
             }
+            // We are no longer tracking the printer.
+            mTrackedPrinterList.remove(printerId);
+            if (mTrackedPrinterList.isEmpty()) {
+                mTrackedPrinterList = null;
+            }
             try {
                 mPrintService.stopPrinterStateTracking(printerId);
             } catch (RemoteException re) {
@@ -461,6 +484,10 @@
         }
         mBinding = false;
         mPendingCommands.clear();
+        mHasActivePrintJobs = false;
+        mHasPrinterDiscoverySession = false;
+        mDiscoveryPriorityList = null;
+        mTrackedPrinterList = null;
         if (isBound()) {
             try {
                 mPrintService.setClient(null);
@@ -500,11 +527,31 @@
                 handleBinderDied();
                 return;
             }
+            // If there is a session, then the service died after creating
+            // a session. Hence, recreate the session.
+            if (mHasPrinterDiscoverySession) {
+                handleCreatePrinterDiscoverySession();
+            }
+            // If there is a priority list, then the service died during
+            // discovery and is restarted. Hence, start discovery.
+            if (mDiscoveryPriorityList != null) {
+                handleStartPrinterDiscovery(mDiscoveryPriorityList);
+            }
+            // If there is a tracked printer list, then the service died
+            // during discovery and is restarted. Hence, start tracking.
+            if (mTrackedPrinterList != null) {
+                final int trackedPrinterCount = mTrackedPrinterList.size();
+                for (int i = 0; i < trackedPrinterCount; i++) {
+                    handleStartPrinterStateTracking(mTrackedPrinterList.get(i));
+                }
+            }
+            // Finally, do all the pending work.
             final int pendingCommandCount = mPendingCommands.size();
             for (int i = 0; i < pendingCommandCount; i++) {
                 Runnable pendingCommand = mPendingCommands.get(i);
                 pendingCommand.run();
             }
+            mPendingCommands.clear();
         }
 
         @Override
@@ -677,7 +724,7 @@
                 throwIfPrinterIdsForPrinterInfoTampered(service.mComponentName, printers);
                 final long identity = Binder.clearCallingIdentity();
                 try {
-                    service.mUserState.onPrintersAdded(printers);
+                    service.mCallbacks.onPrintersAdded(printers);
                 } finally {
                     Binder.restoreCallingIdentity(identity);
                 }
@@ -691,7 +738,7 @@
                 throwIfPrinterIdsTampered(service.mComponentName, printerIds);
                 final long identity = Binder.clearCallingIdentity();
                 try {
-                    service.mUserState.onPrintersRemoved(printerIds);
+                    service.mCallbacks.onPrintersRemoved(printerIds);
                 } finally {
                     Binder.restoreCallingIdentity(identity);
                 }
diff --git a/services/java/com/android/server/print/RemotePrintSpooler.java b/services/java/com/android/server/print/RemotePrintSpooler.java
index 28a6186..45469ac 100644
--- a/services/java/com/android/server/print/RemotePrintSpooler.java
+++ b/services/java/com/android/server/print/RemotePrintSpooler.java
@@ -21,7 +21,6 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.os.Binder;
-import android.os.Build;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
@@ -57,7 +56,7 @@
 
     private static final String LOG_TAG = "RemotePrintSpooler";
 
-    private static final boolean DEBUG = true && Build.IS_DEBUGGABLE;
+    private static final boolean DEBUG = false;
 
     private static final long BIND_SPOOLER_SERVICE_TIMEOUT = 10000;
 
diff --git a/services/java/com/android/server/print/UserState.java b/services/java/com/android/server/print/UserState.java
index 5392975..70fe370 100644
--- a/services/java/com/android/server/print/UserState.java
+++ b/services/java/com/android/server/print/UserState.java
@@ -23,7 +23,8 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
-import android.os.Build;
+import android.os.AsyncTask;
+import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -32,6 +33,7 @@
 import android.os.RemoteException;
 import android.print.IPrinterDiscoveryObserver;
 import android.print.PrintJobInfo;
+import android.print.PrintManager;
 import android.print.PrinterId;
 import android.print.PrinterInfo;
 import android.printservice.PrintServiceInfo;
@@ -43,7 +45,9 @@
 import android.util.Log;
 import android.util.Slog;
 
+import com.android.internal.R;
 import com.android.internal.os.SomeArgs;
+import com.android.server.print.RemotePrintService.PrintServiceCallbacks;
 import com.android.server.print.RemotePrintSpooler.PrintSpoolerCallbacks;
 
 import java.io.FileDescriptor;
@@ -58,11 +62,11 @@
 /**
  * Represents the print state for a user.
  */
-final class UserState implements PrintSpoolerCallbacks {
+final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
 
     private static final String LOG_TAG = "UserState";
 
-    private static final boolean DEBUG = true && Build.IS_DEBUGGABLE;
+    private static final boolean DEBUG = false;
 
     private static final int MAX_ITEMS_PER_CALLBACK = 50;
 
@@ -246,6 +250,7 @@
         }
     }
 
+    @Override
     public void onPrintersAdded(List<PrinterInfo> printers) {
         synchronized (mLock) {
             throwIfDestroyedLocked();
@@ -257,11 +262,11 @@
             if (mPrinterDiscoverySession == null) {
                 return;
             }
-            // Request an updated.
             mPrinterDiscoverySession.onPrintersAddedLocked(printers);
         }
     }
 
+    @Override
     public void onPrintersRemoved(List<PrinterId> printerIds) {
         synchronized (mLock) {
             throwIfDestroyedLocked();
@@ -273,11 +278,28 @@
             if (mPrinterDiscoverySession == null) {
                 return;
             }
-            // Request an updated.
             mPrinterDiscoverySession.onPrintersRemovedLocked(printerIds);
         }
     }
 
+    @Override
+    public void onServiceDied(RemotePrintService service) {
+        synchronized (mLock) {
+            throwIfDestroyedLocked();
+            // No services - nothing to do.
+            if (mActiveServices.isEmpty()) {
+                return;
+            }
+            // Fail all print jobs.
+            failActivePrintJobsForService(service.getComponentName());
+            // No session - nothing to do.
+            if (mPrinterDiscoverySession == null) {
+                return;
+            }
+            mPrinterDiscoverySession.onServiceDiedLocked(service);
+        }
+    }
+
     public void updateIfNeededLocked() {
         throwIfDestroyedLocked();
         if (readConfigurationLocked()) {
@@ -516,23 +538,72 @@
                 if (!mActiveServices.containsKey(serviceName)) {
                     RemotePrintService service = new RemotePrintService(
                             mContext, serviceName, mUserId, mSpooler, this);
-                    mActiveServices.put(serviceName, service);
-                    if (mPrinterDiscoverySession != null) {
-                        mPrinterDiscoverySession.onServiceAddedLocked(service);
-                    }
+                    addServiceLocked(service);
                 }
             } else {
                 RemotePrintService service = mActiveServices.remove(serviceName);
                 if (service != null) {
-                    service.destroy();
-                    if (mPrinterDiscoverySession != null) {
-                        mPrinterDiscoverySession.onServiceRemovedLocked(serviceName);
-                    }
+                    removeServiceLocked(service);
                 }
             }
         }
     }
 
+    private void addServiceLocked(RemotePrintService service) {
+        mActiveServices.put(service.getComponentName(), service);
+        if (mPrinterDiscoverySession != null) {
+            mPrinterDiscoverySession.onServiceAddedLocked(service);
+        }
+    }
+
+    private void removeServiceLocked(RemotePrintService service) {
+        // Fail all print jobs.
+        failActivePrintJobsForService(service.getComponentName());
+        // If discovery is in progress, tear down the service.
+        if (mPrinterDiscoverySession != null) {
+            mPrinterDiscoverySession.onServiceRemovedLocked(service);
+        } else {
+            // Otherwise, just destroy it.
+            service.destroy();
+        }
+    }
+
+    private void failActivePrintJobsForService(final ComponentName serviceName) {
+        // Makes sure all active print jobs are failed since the service
+        // just died. Do this off the main thread since we do to allow
+        // calls into the spooler on the main thread.
+        if (Looper.getMainLooper().isCurrentThread()) {
+            new AsyncTask<Void, Void, Void>() {
+                @Override
+                protected Void doInBackground(Void... params) {
+                    failActivePrintJobsForServiceInternal(serviceName);
+                    return null;
+                }
+            }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
+        } else {
+            failActivePrintJobsForServiceInternal(serviceName);
+        }
+    }
+
+    private void failActivePrintJobsForServiceInternal(ComponentName serviceName) {
+        List<PrintJobInfo> printJobs = mSpooler.getPrintJobInfos(serviceName,
+                PrintJobInfo.STATE_ANY_ACTIVE, PrintManager.APP_ID_ANY);
+        if (printJobs == null) {
+            return;
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            final int printJobCount = printJobs.size();
+            for (int i = 0; i < printJobCount; i++) {
+                PrintJobInfo printJob = printJobs.get(i);
+                mSpooler.setPrintJobState(printJob.getId(), PrintJobInfo.STATE_FAILED,
+                        mContext.getString(R.string.reason_unknown));
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
     private void throwIfDestroyedLocked() {
         if (mDestroyed) {
             throw new IllegalStateException("Cannot interact with a destroyed instance.");
@@ -603,17 +674,18 @@
                 return;
             }
 
-            // If printer discovery is ongoing and the start request has a list
-            // of printer to be checked, then we just request validating them.
-            if (!mStartedPrinterDiscoveryTokens.isEmpty()
-                    && priorityList != null && !priorityList.isEmpty()) {
-                validatePrinters(priorityList);
-                return;
-            }
+            final boolean discoveryStarted = !mStartedPrinterDiscoveryTokens.isEmpty();
 
             // Remember we got a start request to match with an end.
             mStartedPrinterDiscoveryTokens.add(observer.asBinder());
 
+            // If printer discovery is ongoing and the start request has a list
+            // of printer to be checked, then we just request validating them.
+            if (discoveryStarted && priorityList != null && !priorityList.isEmpty()) {
+                validatePrinters(priorityList);
+                return;
+            }
+
             // The service are already performing discovery - nothing to do.
             if (mStartedPrinterDiscoveryTokens.size() > 1) {
                 return;
@@ -822,32 +894,20 @@
             }
         }
 
-        public void onServiceRemovedLocked(ComponentName serviceName) {
+        public void onServiceRemovedLocked(RemotePrintService service) {
             if (mIsDestroyed) {
                 Log.w(LOG_TAG, "Not updating removed service - session destroyed");
                 return;
             }
-            // No printers - nothing to do.
-            if (mPrinters.isEmpty()) {
-                return;
-            }
-            // Remove the printers for that service.
-            List<PrinterId> removedPrinterIds = null;
-            final int printerCount = mPrinters.size();
-            for (int i = 0; i < printerCount; i++) {
-                PrinterId printerId = mPrinters.keyAt(i);
-                if (printerId.getServiceName().equals(serviceName)) {
-                    if (removedPrinterIds == null) {
-                        removedPrinterIds = new ArrayList<PrinterId>();
-                    }
-                    removedPrinterIds.add(printerId);
-                }
-            }
-            if (!removedPrinterIds.isEmpty()) {
-                mHandler.obtainMessage(
-                        SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED,
-                        removedPrinterIds).sendToTarget();
-            }
+            // Remove the reported and tracked printers for that service.
+            ComponentName serviceName = service.getComponentName();
+            removePrintersForServiceLocked(serviceName);
+            service.destroy();
+        }
+
+        public void onServiceDiedLocked(RemotePrintService service) {
+            // Remove the reported by that service.
+            removePrintersForServiceLocked(service.getComponentName());
         }
 
         public void onServiceAddedLocked(RemotePrintService service) {
@@ -908,6 +968,34 @@
             }
         }
 
+        private void removePrintersForServiceLocked(ComponentName serviceName) {
+            // No printers - nothing to do.
+            if (mPrinters.isEmpty()) {
+                return;
+            }
+            // Remove the printers for that service.
+            List<PrinterId> removedPrinterIds = null;
+            final int printerCount = mPrinters.size();
+            for (int i = 0; i < printerCount; i++) {
+                PrinterId printerId = mPrinters.keyAt(i);
+                if (printerId.getServiceName().equals(serviceName)) {
+                    if (removedPrinterIds == null) {
+                        removedPrinterIds = new ArrayList<PrinterId>();
+                    }
+                    removedPrinterIds.add(printerId);
+                }
+            }
+            final int removedPrinterCount = removedPrinterIds.size();
+            for (int i = 0; i < removedPrinterCount; i++) {
+                mPrinters.remove(removedPrinterIds.get(i));
+            }
+            if (removedPrinterIds != null) {
+                mHandler.obtainMessage(
+                        SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED,
+                        removedPrinterIds).sendToTarget();
+            }
+        }
+
         private void handleDispatchPrintersAdded(List<PrinterInfo> addedPrinters) {
             final int observerCount = mDiscoveryObservers.beginBroadcast();
             for (int i = 0; i < observerCount; i++) {
@@ -1026,14 +1114,17 @@
             public static final int MSG_DISPATCH_PRINTERS_REMOVED = 4;
 
             public static final int MSG_CREATE_PRINTER_DISCOVERY_SESSION = 5;
-            public static final int MSG_START_PRINTER_DISCOVERY = 6;
-            public static final int MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION = 7;
-            public static final int MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION = 8;
-            public static final int MSG_DISPATCH_START_PRINTER_DISCOVERY = 9;
-            public static final int MSG_DISPATCH_STOP_PRINTER_DISCOVERY = 10;
-            public static final int MSG_VALIDATE_PRINTERS = 11;
-            public static final int MSG_START_PRINTER_STATE_TRACKING = 12;
-            public static final int MSG_STOP_PRINTER_STATE_TRACKING = 13;
+            public static final int MSG_DESTROY_PRINTER_DISCOVERY_SESSION = 6;
+            public static final int MSG_START_PRINTER_DISCOVERY = 7;
+            public static final int MSG_STOP_PRINTER_DISCOVERY = 8;
+            public static final int MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION = 9;
+            public static final int MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION = 10;
+            public static final int MSG_DISPATCH_START_PRINTER_DISCOVERY = 11;
+            public static final int MSG_DISPATCH_STOP_PRINTER_DISCOVERY = 12;
+            public static final int MSG_VALIDATE_PRINTERS = 13;
+            public static final int MSG_START_PRINTER_STATE_TRACKING = 14;
+            public static final int MSG_STOP_PRINTER_STATE_TRACKING = 15;
+            public static final int MSG_DESTROY_SERVICE = 16;
 
             SessionHandler(Looper looper) {
                 super(looper, null, false);
@@ -1074,11 +1165,21 @@
                         service.createPrinterDiscoverySession();
                     } break;
 
+                    case MSG_DESTROY_PRINTER_DISCOVERY_SESSION: {
+                        RemotePrintService service = (RemotePrintService) message.obj;
+                        service.destroyPrinterDiscoverySession();
+                    } break;
+
                     case MSG_START_PRINTER_DISCOVERY: {
                         RemotePrintService service = (RemotePrintService) message.obj;
                         service.startPrinterDiscovery(null);
                     } break;
 
+                    case MSG_STOP_PRINTER_DISCOVERY: {
+                        RemotePrintService service = (RemotePrintService) message.obj;
+                        service.stopPrinterDiscovery();
+                    } break;
+
                     case MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION: {
                         List<RemotePrintService> services = (List<RemotePrintService>) message.obj;
                         handleDispatchCreatePrinterDiscoverySession(services);
@@ -1124,7 +1225,12 @@
                         PrinterId printerId = (PrinterId) args.arg2;
                         args.recycle();
                         handleStopPrinterStateTracking(service, printerId);
-                    }
+                    } break;
+
+                    case MSG_DESTROY_SERVICE: {
+                        RemotePrintService service = (RemotePrintService) message.obj;
+                        service.destroy();
+                    } break;
                 }
             }
         }