diff options
Diffstat (limited to 'services/print/java/com/android/server/print/RemotePrintService.java')
-rw-r--r-- | services/print/java/com/android/server/print/RemotePrintService.java | 806 |
1 files changed, 806 insertions, 0 deletions
diff --git a/services/print/java/com/android/server/print/RemotePrintService.java b/services/print/java/com/android/server/print/RemotePrintService.java new file mode 100644 index 0000000..1bb61d2 --- /dev/null +++ b/services/print/java/com/android/server/print/RemotePrintService.java @@ -0,0 +1,806 @@ +/* + * Copyright (C) 2013 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.server.print; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.content.pm.ParceledListSlice; +import android.os.Binder; +import android.os.Handler; +import android.os.IBinder; +import android.os.IBinder.DeathRecipient; +import android.os.Looper; +import android.os.Message; +import android.os.ParcelFileDescriptor; +import android.os.RemoteException; +import android.os.UserHandle; +import android.print.PrintJobId; +import android.print.PrintJobInfo; +import android.print.PrintManager; +import android.print.PrinterId; +import android.print.PrinterInfo; +import android.printservice.IPrintService; +import android.printservice.IPrintServiceClient; +import android.util.Slog; + +import java.io.PrintWriter; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; + +/** + * This class represents a remote print service. It abstracts away the binding + * and unbinding from the remote implementation. Clients can call methods of + * this class without worrying about when and how to bind/unbind. + */ +final class RemotePrintService implements DeathRecipient { + + private static final String LOG_TAG = "RemotePrintService"; + + private static final boolean DEBUG = false; + + private final Context mContext; + + private final ComponentName mComponentName; + + private final Intent mIntent; + + private final RemotePrintSpooler mSpooler; + + private final PrintServiceCallbacks mCallbacks; + + private final int mUserId; + + private final List<Runnable> mPendingCommands = new ArrayList<Runnable>(); + + private final ServiceConnection mServiceConnection = new RemoteServiceConneciton(); + + private final RemotePrintServiceClient mPrintServiceClient; + + private final Handler mHandler; + + private IPrintService mPrintService; + + private boolean mBinding; + + private boolean mDestroyed; + + private boolean mHasActivePrintJobs; + + private boolean mHasPrinterDiscoverySession; + + private boolean mServiceDied; + + 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, PrintServiceCallbacks callbacks) { + mContext = context; + mCallbacks = callbacks; + mComponentName = componentName; + mIntent = new Intent().setComponent(mComponentName); + mUserId = userId; + mSpooler = spooler; + mHandler = new MyHandler(context.getMainLooper()); + 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(); + + // Done + mDestroyed = true; + } + + @Override + public void binderDied() { + mHandler.sendEmptyMessage(MyHandler.MSG_BINDER_DIED); + } + + private void handleBinderDied() { + mPrintService.asBinder().unlinkToDeath(this, 0); + mPrintService = null; + mServiceDied = true; + mCallbacks.onServiceDied(this); + } + + public void onAllPrintJobsHandled() { + mHandler.sendEmptyMessage(MyHandler.MSG_ON_ALL_PRINT_JOBS_HANDLED); + } + + private void handleOnAllPrintJobsHandled() { + throwIfDestroyed(); + mHasActivePrintJobs = false; + if (!isBound()) { + // The service is dead and neither has active jobs nor discovery + // session, so ensure we are unbound since the service has no work. + if (mServiceDied && !mHasPrinterDiscoverySession) { + ensureUnbound(); + return; + } + ensureBound(); + mPendingCommands.add(new Runnable() { + @Override + public void run() { + handleOnAllPrintJobsHandled(); + } + }); + } else { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserId + "] onAllPrintJobsHandled()"); + } + // If the service has a printer discovery session + // created we should not disconnect from it just yet. + if (!mHasPrinterDiscoverySession) { + ensureUnbound(); + } + } + } + + public void onRequestCancelPrintJob(PrintJobInfo printJob) { + mHandler.obtainMessage(MyHandler.MSG_ON_REQUEST_CANCEL_PRINT_JOB, + printJob).sendToTarget(); + } + + private void handleRequestCancelPrintJob(final PrintJobInfo printJob) { + throwIfDestroyed(); + if (!isBound()) { + ensureBound(); + mPendingCommands.add(new Runnable() { + @Override + public void run() { + handleRequestCancelPrintJob(printJob); + } + }); + } else { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserId + "] requestCancelPrintJob()"); + } + try { + mPrintService.requestCancelPrintJob(printJob); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error canceling a pring job.", re); + } + } + } + + public void onPrintJobQueued(PrintJobInfo printJob) { + mHandler.obtainMessage(MyHandler.MSG_ON_PRINT_JOB_QUEUED, + printJob).sendToTarget(); + } + + private void handleOnPrintJobQueued(final PrintJobInfo printJob) { + throwIfDestroyed(); + mHasActivePrintJobs = true; + if (!isBound()) { + ensureBound(); + mPendingCommands.add(new Runnable() { + @Override + public void run() { + handleOnPrintJobQueued(printJob); + } + }); + } else { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserId + "] onPrintJobQueued()"); + } + try { + mPrintService.onPrintJobQueued(printJob); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error announcing queued pring job.", re); + } + } + } + + public void createPrinterDiscoverySession() { + mHandler.sendEmptyMessage(MyHandler.MSG_CREATE_PRINTER_DISCOVERY_SESSION); + } + + private void handleCreatePrinterDiscoverySession() { + throwIfDestroyed(); + mHasPrinterDiscoverySession = true; + if (!isBound()) { + ensureBound(); + mPendingCommands.add(new Runnable() { + @Override + public void run() { + handleCreatePrinterDiscoverySession(); + } + }); + } else { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserId + "] createPrinterDiscoverySession()"); + } + try { + mPrintService.createPrinterDiscoverySession(); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error creating printer dicovery session.", re); + } + } + } + + public void destroyPrinterDiscoverySession() { + mHandler.sendEmptyMessage(MyHandler.MSG_DESTROY_PRINTER_DISCOVERY_SESSION); + } + + private void handleDestroyPrinterDiscoverySession() { + throwIfDestroyed(); + mHasPrinterDiscoverySession = false; + if (!isBound()) { + // The service is dead and neither has active jobs nor discovery + // session, so ensure we are unbound since the service has no work. + if (mServiceDied && !mHasActivePrintJobs) { + ensureUnbound(); + return; + } + ensureBound(); + mPendingCommands.add(new Runnable() { + @Override + public void run() { + handleDestroyPrinterDiscoverySession(); + } + }); + } else { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserId + "] destroyPrinterDiscoverySession()"); + } + try { + mPrintService.destroyPrinterDiscoverySession(); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error destroying printer dicovery session.", re); + } + // If the service has no print jobs and no active discovery + // session anymore we should disconnect from it. + if (!mHasActivePrintJobs) { + ensureUnbound(); + } + } + } + + public void startPrinterDiscovery(List<PrinterId> priorityList) { + mHandler.obtainMessage(MyHandler.MSG_START_PRINTER_DISCOVERY, + priorityList).sendToTarget(); + } + + private void handleStartPrinterDiscovery(final List<PrinterId> priorityList) { + throwIfDestroyed(); + // Take a note that we are doing discovery. + mDiscoveryPriorityList = new ArrayList<PrinterId>(); + if (priorityList != null) { + mDiscoveryPriorityList.addAll(priorityList); + } + if (!isBound()) { + ensureBound(); + mPendingCommands.add(new Runnable() { + @Override + public void run() { + handleStartPrinterDiscovery(priorityList); + } + }); + } else { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserId + "] startPrinterDiscovery()"); + } + try { + mPrintService.startPrinterDiscovery(priorityList); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error starting printer dicovery.", re); + } + } + } + + public void stopPrinterDiscovery() { + mHandler.sendEmptyMessage(MyHandler.MSG_STOP_PRINTER_DISCOVERY); + } + + private void handleStopPrinterDiscovery() { + throwIfDestroyed(); + // We are not doing discovery anymore. + mDiscoveryPriorityList = null; + if (!isBound()) { + ensureBound(); + mPendingCommands.add(new Runnable() { + @Override + public void run() { + handleStopPrinterDiscovery(); + } + }); + } else { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserId + "] stopPrinterDiscovery()"); + } + try { + mPrintService.stopPrinterDiscovery(); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error stopping printer dicovery.", re); + } + } + } + + public void validatePrinters(List<PrinterId> printerIds) { + mHandler.obtainMessage(MyHandler.MSG_VALIDATE_PRINTERS, + printerIds).sendToTarget(); + } + + private void handleValidatePrinters(final List<PrinterId> printerIds) { + throwIfDestroyed(); + if (!isBound()) { + ensureBound(); + mPendingCommands.add(new Runnable() { + @Override + public void run() { + handleValidatePrinters(printerIds); + } + }); + } else { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserId + "] validatePrinters()"); + } + try { + mPrintService.validatePrinters(printerIds); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error requesting printers validation.", re); + } + } + } + + public void startPrinterStateTracking(PrinterId printerId) { + mHandler.obtainMessage(MyHandler.MSG_START_PRINTER_STATE_TRACKING, + printerId).sendToTarget(); + } + + private void handleStartPrinterStateTracking(final PrinterId printerId) { + throwIfDestroyed(); + // Take a note we are tracking the printer. + if (mTrackedPrinterList == null) { + mTrackedPrinterList = new ArrayList<PrinterId>(); + } + mTrackedPrinterList.add(printerId); + if (!isBound()) { + ensureBound(); + mPendingCommands.add(new Runnable() { + @Override + public void run() { + handleStartPrinterStateTracking(printerId); + } + }); + } else { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserId + "] startPrinterTracking()"); + } + try { + mPrintService.startPrinterStateTracking(printerId); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error requesting start printer tracking.", re); + } + } + } + + public void stopPrinterStateTracking(PrinterId printerId) { + mHandler.obtainMessage(MyHandler.MSG_STOP_PRINTER_STATE_TRACKING, + printerId).sendToTarget(); + } + + private void handleStopPrinterStateTracking(final PrinterId printerId) { + throwIfDestroyed(); + // 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() { + @Override + public void run() { + handleStopPrinterStateTracking(printerId); + } + }); + } else { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserId + "] stopPrinterTracking()"); + } + try { + mPrintService.stopPrinterStateTracking(printerId); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error requesting stop printer tracking.", re); + } + } + } + + public void dump(PrintWriter pw, String prefix) { + String tab = " "; + pw.append(prefix).append("service:").println(); + pw.append(prefix).append(tab).append("componentName=") + .append(mComponentName.flattenToString()).println(); + pw.append(prefix).append(tab).append("destroyed=") + .append(String.valueOf(mDestroyed)).println(); + pw.append(prefix).append(tab).append("bound=") + .append(String.valueOf(isBound())).println(); + pw.append(prefix).append(tab).append("hasDicoverySession=") + .append(String.valueOf(mHasPrinterDiscoverySession)).println(); + pw.append(prefix).append(tab).append("hasActivePrintJobs=") + .append(String.valueOf(mHasActivePrintJobs)).println(); + pw.append(prefix).append(tab).append("isDiscoveringPrinters=") + .append(String.valueOf(mDiscoveryPriorityList != null)).println(); + pw.append(prefix).append(tab).append("trackedPrinters=") + .append((mTrackedPrinterList != null) ? mTrackedPrinterList.toString() : "null"); + } + + private boolean isBound() { + return mPrintService != null; + } + + private void ensureBound() { + if (isBound() || mBinding) { + return; + } + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserId + "] ensureBound()"); + } + mBinding = true; + mContext.bindServiceAsUser(mIntent, mServiceConnection, + Context.BIND_AUTO_CREATE, new UserHandle(mUserId)); + } + + private void ensureUnbound() { + if (!isBound() && !mBinding) { + return; + } + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserId + "] ensureUnbound()"); + } + mBinding = false; + mPendingCommands.clear(); + mHasActivePrintJobs = false; + mHasPrinterDiscoverySession = false; + mDiscoveryPriorityList = null; + mTrackedPrinterList = null; + if (isBound()) { + try { + mPrintService.setClient(null); + } catch (RemoteException re) { + /* ignore */ + } + mPrintService.asBinder().unlinkToDeath(this, 0); + mPrintService = null; + mContext.unbindService(mServiceConnection); + } + } + + private void throwIfDestroyed() { + if (mDestroyed) { + throw new IllegalStateException("Cannot interact with a destroyed service"); + } + } + + private class RemoteServiceConneciton implements ServiceConnection { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + if (mDestroyed || !mBinding) { + mContext.unbindService(mServiceConnection); + return; + } + mBinding = false; + mPrintService = IPrintService.Stub.asInterface(service); + try { + service.linkToDeath(RemotePrintService.this, 0); + } catch (RemoteException re) { + handleBinderDied(); + return; + } + try { + mPrintService.setClient(mPrintServiceClient); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error setting client for: " + service, re); + handleBinderDied(); + return; + } + // If the service died and there is a discovery session, recreate it. + if (mServiceDied && mHasPrinterDiscoverySession) { + handleCreatePrinterDiscoverySession(); + } + // If the service died and there is discovery started, restart it. + 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)); + } + } + // Finally, do all the pending work. + while (!mPendingCommands.isEmpty()) { + Runnable pendingCommand = mPendingCommands.remove(0); + pendingCommand.run(); + } + // We did a best effort to get to the last state if we crashed. + // If we do not have print jobs and no discovery is in progress, + // then no need to be bound. + if (!mHasPrinterDiscoverySession && !mHasActivePrintJobs) { + ensureUnbound(); + } + mServiceDied = false; + } + + @Override + public void onServiceDisconnected(ComponentName name) { + mBinding = true; + } + } + + private final class MyHandler extends Handler { + public static final int MSG_CREATE_PRINTER_DISCOVERY_SESSION = 1; + public static final int MSG_DESTROY_PRINTER_DISCOVERY_SESSION = 2; + public static final int MSG_START_PRINTER_DISCOVERY = 3; + public static final int MSG_STOP_PRINTER_DISCOVERY = 4; + public static final int MSG_VALIDATE_PRINTERS = 5; + public static final int MSG_START_PRINTER_STATE_TRACKING = 6; + public static final int MSG_STOP_PRINTER_STATE_TRACKING = 7; + public static final int MSG_ON_ALL_PRINT_JOBS_HANDLED = 8; + public static final int MSG_ON_REQUEST_CANCEL_PRINT_JOB = 9; + public static final int MSG_ON_PRINT_JOB_QUEUED = 10; + public static final int MSG_DESTROY = 11; + public static final int MSG_BINDER_DIED = 12; + + public MyHandler(Looper looper) { + super(looper, null, false); + } + + @Override + @SuppressWarnings("unchecked") + public void handleMessage(Message message) { + switch (message.what) { + case MSG_CREATE_PRINTER_DISCOVERY_SESSION: { + handleCreatePrinterDiscoverySession(); + } break; + + case MSG_DESTROY_PRINTER_DISCOVERY_SESSION: { + handleDestroyPrinterDiscoverySession(); + } break; + + case MSG_START_PRINTER_DISCOVERY: { + List<PrinterId> priorityList = (ArrayList<PrinterId>) message.obj; + handleStartPrinterDiscovery(priorityList); + } break; + + case MSG_STOP_PRINTER_DISCOVERY: { + handleStopPrinterDiscovery(); + } break; + + case MSG_VALIDATE_PRINTERS: { + List<PrinterId> printerIds = (List<PrinterId>) message.obj; + handleValidatePrinters(printerIds); + } break; + + case MSG_START_PRINTER_STATE_TRACKING: { + PrinterId printerId = (PrinterId) message.obj; + handleStartPrinterStateTracking(printerId); + } break; + + case MSG_STOP_PRINTER_STATE_TRACKING: { + PrinterId printerId = (PrinterId) message.obj; + handleStopPrinterStateTracking(printerId); + } break; + + case MSG_ON_ALL_PRINT_JOBS_HANDLED: { + handleOnAllPrintJobsHandled(); + } break; + + case MSG_ON_REQUEST_CANCEL_PRINT_JOB: { + PrintJobInfo printJob = (PrintJobInfo) message.obj; + handleRequestCancelPrintJob(printJob); + } break; + + case MSG_ON_PRINT_JOB_QUEUED: { + PrintJobInfo printJob = (PrintJobInfo) message.obj; + handleOnPrintJobQueued(printJob); + } break; + + case MSG_DESTROY: { + handleDestroy(); + } break; + + case MSG_BINDER_DIED: { + handleBinderDied(); + } break; + } + } + } + + private static final class RemotePrintServiceClient extends IPrintServiceClient.Stub { + private final WeakReference<RemotePrintService> mWeakService; + + public RemotePrintServiceClient(RemotePrintService service) { + mWeakService = new WeakReference<RemotePrintService>(service); + } + + @Override + public List<PrintJobInfo> getPrintJobInfos() { + RemotePrintService service = mWeakService.get(); + if (service != null) { + final long identity = Binder.clearCallingIdentity(); + try { + return service.mSpooler.getPrintJobInfos(service.mComponentName, + PrintJobInfo.STATE_ANY_SCHEDULED, PrintManager.APP_ID_ANY); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + return null; + } + + @Override + public PrintJobInfo getPrintJobInfo(PrintJobId printJobId) { + RemotePrintService service = mWeakService.get(); + if (service != null) { + final long identity = Binder.clearCallingIdentity(); + try { + return service.mSpooler.getPrintJobInfo(printJobId, + PrintManager.APP_ID_ANY); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + return null; + } + + @Override + public boolean setPrintJobState(PrintJobId printJobId, int state, String error) { + RemotePrintService service = mWeakService.get(); + if (service != null) { + final long identity = Binder.clearCallingIdentity(); + try { + return service.mSpooler.setPrintJobState(printJobId, state, error); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + return false; + } + + @Override + public boolean setPrintJobTag(PrintJobId printJobId, String tag) { + RemotePrintService service = mWeakService.get(); + if (service != null) { + final long identity = Binder.clearCallingIdentity(); + try { + return service.mSpooler.setPrintJobTag(printJobId, tag); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + return false; + } + + @Override + public void writePrintJobData(ParcelFileDescriptor fd, PrintJobId printJobId) { + RemotePrintService service = mWeakService.get(); + if (service != null) { + final long identity = Binder.clearCallingIdentity(); + try { + service.mSpooler.writePrintJobData(fd, printJobId); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + } + + @Override + @SuppressWarnings({"rawtypes", "unchecked"}) + public void onPrintersAdded(ParceledListSlice printers) { + RemotePrintService service = mWeakService.get(); + if (service != null) { + List<PrinterInfo> addedPrinters = (List<PrinterInfo>) printers.getList(); + throwIfPrinterIdsForPrinterInfoTampered(service.mComponentName, addedPrinters); + final long identity = Binder.clearCallingIdentity(); + try { + service.mCallbacks.onPrintersAdded(addedPrinters); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + } + + @Override + @SuppressWarnings({"rawtypes", "unchecked"}) + public void onPrintersRemoved(ParceledListSlice printerIds) { + RemotePrintService service = mWeakService.get(); + if (service != null) { + List<PrinterId> removedPrinterIds = (List<PrinterId>) printerIds.getList(); + throwIfPrinterIdsTampered(service.mComponentName, removedPrinterIds); + final long identity = Binder.clearCallingIdentity(); + try { + service.mCallbacks.onPrintersRemoved(removedPrinterIds); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + } + + private void throwIfPrinterIdsForPrinterInfoTampered(ComponentName serviceName, + List<PrinterInfo> printerInfos) { + final int printerInfoCount = printerInfos.size(); + for (int i = 0; i < printerInfoCount; i++) { + PrinterId printerId = printerInfos.get(i).getId(); + throwIfPrinterIdTampered(serviceName, printerId); + } + } + + private void throwIfPrinterIdsTampered(ComponentName serviceName, + List<PrinterId> printerIds) { + final int printerIdCount = printerIds.size(); + for (int i = 0; i < printerIdCount; i++) { + PrinterId printerId = printerIds.get(i); + throwIfPrinterIdTampered(serviceName, printerId); + } + } + + private void throwIfPrinterIdTampered(ComponentName serviceName, PrinterId printerId) { + if (printerId == null || printerId.getServiceName() == null + || !printerId.getServiceName().equals(serviceName)) { + throw new IllegalArgumentException("Invalid printer id: " + printerId); + } + } + } +} |