RemotePrintService.java revision c6066799ad130140159230d14451b429eb828755
1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server.print; 18 19import android.content.ComponentName; 20import android.content.Context; 21import android.content.Intent; 22import android.content.ServiceConnection; 23import android.os.Binder; 24import android.os.Handler; 25import android.os.IBinder; 26import android.os.IBinder.DeathRecipient; 27import android.os.Looper; 28import android.os.Message; 29import android.os.ParcelFileDescriptor; 30import android.os.RemoteException; 31import android.os.UserHandle; 32import android.print.PrintJobInfo; 33import android.print.PrintManager; 34import android.print.PrinterId; 35import android.print.PrinterInfo; 36import android.printservice.IPrintService; 37import android.printservice.IPrintServiceClient; 38import android.util.Slog; 39 40import java.io.PrintWriter; 41import java.lang.ref.WeakReference; 42import java.util.ArrayList; 43import java.util.List; 44 45/** 46 * This class represents a remote print service. It abstracts away the binding 47 * and unbinding from the remote implementation. Clients can call methods of 48 * this class without worrying about when and how to bind/unbind. 49 */ 50final class RemotePrintService implements DeathRecipient { 51 52 private static final String LOG_TAG = "RemotePrintService"; 53 54 private static final boolean DEBUG = false; 55 56 private final Context mContext; 57 58 private final ComponentName mComponentName; 59 60 private final Intent mIntent; 61 62 private final RemotePrintSpooler mSpooler; 63 64 private final PrintServiceCallbacks mCallbacks; 65 66 private final int mUserId; 67 68 private final List<Runnable> mPendingCommands = new ArrayList<Runnable>(); 69 70 private final ServiceConnection mServiceConnection = new RemoteServiceConneciton(); 71 72 private final RemotePrintServiceClient mPrintServiceClient; 73 74 private final Handler mHandler; 75 76 private IPrintService mPrintService; 77 78 private boolean mBinding; 79 80 private boolean mDestroyed; 81 82 private boolean mHasActivePrintJobs; 83 84 private boolean mHasPrinterDiscoverySession; 85 86 private List<PrinterId> mDiscoveryPriorityList; 87 88 private List<PrinterId> mTrackedPrinterList; 89 90 public static interface PrintServiceCallbacks { 91 public void onPrintersAdded(List<PrinterInfo> printers); 92 public void onPrintersRemoved(List<PrinterId> printerIds); 93 public void onServiceDied(RemotePrintService service); 94 } 95 96 public RemotePrintService(Context context, ComponentName componentName, int userId, 97 RemotePrintSpooler spooler, PrintServiceCallbacks callbacks) { 98 mContext = context; 99 mCallbacks = callbacks; 100 mComponentName = componentName; 101 mIntent = new Intent().setComponent(mComponentName); 102 mUserId = userId; 103 mSpooler = spooler; 104 mHandler = new MyHandler(context.getMainLooper()); 105 mPrintServiceClient = new RemotePrintServiceClient(this); 106 } 107 108 public ComponentName getComponentName() { 109 return mComponentName; 110 } 111 112 public void destroy() { 113 mHandler.sendEmptyMessage(MyHandler.MSG_DESTROY); 114 } 115 116 private void handleDestroy() { 117 throwIfDestroyed(); 118 119 // Stop tracking printers. 120 if (mTrackedPrinterList != null) { 121 final int trackedPrinterCount = mTrackedPrinterList.size(); 122 for (int i = 0; i < trackedPrinterCount; i++) { 123 PrinterId printerId = mTrackedPrinterList.get(i); 124 if (printerId.getServiceName().equals(mComponentName)) { 125 handleStopPrinterStateTracking(printerId); 126 } 127 } 128 } 129 130 // Stop printer discovery. 131 if (mDiscoveryPriorityList != null) { 132 handleStopPrinterDiscovery(); 133 } 134 135 // Destroy the discovery session. 136 if (mHasPrinterDiscoverySession) { 137 handleDestroyPrinterDiscoverySession(); 138 } 139 140 // Unbind. 141 ensureUnbound(); 142 143 // Done 144 mDestroyed = true; 145 } 146 147 public void onAllPrintJobsHandled() { 148 mHandler.sendEmptyMessage(MyHandler.MSG_ON_ALL_PRINT_JOBS_HANDLED); 149 } 150 151 @Override 152 public void binderDied() { 153 mHandler.sendEmptyMessage(MyHandler.MSG_BINDER_DIED); 154 } 155 156 private void handleBinderDied() { 157 mPrintService.asBinder().unlinkToDeath(this, 0); 158 mPrintService = null; 159 mCallbacks.onServiceDied(this); 160 } 161 162 public void dump(PrintWriter pw, String prefix) { 163 String tab = " "; 164 pw.append(prefix).append("service:").println(); 165 pw.append(prefix).append(tab).append("componentName=") 166 .append(mComponentName.flattenToString()).println(); 167 pw.append(prefix).append(tab).append("destroyed=") 168 .append(String.valueOf(mDestroyed)).println(); 169 pw.append(prefix).append(tab).append("bound=") 170 .append(String.valueOf(isBound())).println(); 171 pw.append(prefix).append(tab).append("hasDicoverySession=") 172 .append(String.valueOf(mHasPrinterDiscoverySession)).println(); 173 pw.append(prefix).append(tab).append("isDiscoveringPrinters=") 174 .append(String.valueOf(mDiscoveryPriorityList != null)).println(); 175 pw.append(prefix).append(tab).append("trackedPrinters=") 176 .append((mTrackedPrinterList != null) ? mTrackedPrinterList.toString() : "null"); 177 } 178 179 private void handleOnAllPrintJobsHandled() { 180 throwIfDestroyed(); 181 182 mHasActivePrintJobs = false; 183 184 if (isBound()) { 185 if (DEBUG) { 186 Slog.i(LOG_TAG, "[user: " + mUserId + "] onAllPrintJobsHandled()"); 187 } 188 189 // If the service has a printer discovery session 190 // created we should not disconnect from it just yet. 191 if (!mHasPrinterDiscoverySession) { 192 ensureUnbound(); 193 } 194 } 195 } 196 197 public void onRequestCancelPrintJob(PrintJobInfo printJob) { 198 mHandler.obtainMessage(MyHandler.MSG_ON_REQUEST_CANCEL_PRINT_JOB, 199 printJob).sendToTarget(); 200 } 201 202 private void handleRequestCancelPrintJob(final PrintJobInfo printJob) { 203 throwIfDestroyed(); 204 // If we are not bound, then we have no print jobs to handle 205 // which means that there are no print jobs to be cancelled. 206 if (isBound()) { 207 if (DEBUG) { 208 Slog.i(LOG_TAG, "[user: " + mUserId + "] requestCancelPrintJob()"); 209 } 210 try { 211 mPrintService.requestCancelPrintJob(printJob); 212 } catch (RemoteException re) { 213 Slog.e(LOG_TAG, "Error canceling a pring job.", re); 214 } 215 } 216 } 217 218 public void onPrintJobQueued(PrintJobInfo printJob) { 219 mHandler.obtainMessage(MyHandler.MSG_ON_PRINT_JOB_QUEUED, 220 printJob).sendToTarget(); 221 } 222 223 private void handleOnPrintJobQueued(final PrintJobInfo printJob) { 224 throwIfDestroyed(); 225 226 mHasActivePrintJobs = true; 227 228 if (!isBound()) { 229 ensureBound(); 230 mPendingCommands.add(new Runnable() { 231 @Override 232 public void run() { 233 handleOnPrintJobQueued(printJob); 234 } 235 }); 236 } else { 237 if (DEBUG) { 238 Slog.i(LOG_TAG, "[user: " + mUserId + "] onPrintJobQueued()"); 239 } 240 try { 241 mPrintService.onPrintJobQueued(printJob); 242 } catch (RemoteException re) { 243 Slog.e(LOG_TAG, "Error announcing queued pring job.", re); 244 } 245 } 246 } 247 248 public void createPrinterDiscoverySession() { 249 mHandler.sendEmptyMessage(MyHandler.MSG_CREATE_PRINTER_DISCOVERY_SESSION); 250 } 251 252 private void handleCreatePrinterDiscoverySession() { 253 throwIfDestroyed(); 254 if (!isBound()) { 255 ensureBound(); 256 mPendingCommands.add(new Runnable() { 257 @Override 258 public void run() { 259 handleCreatePrinterDiscoverySession(); 260 } 261 }); 262 } else { 263 if (DEBUG) { 264 Slog.i(LOG_TAG, "[user: " + mUserId + "] createPrinterDiscoverySession()"); 265 } 266 try { 267 mPrintService.createPrinterDiscoverySession(); 268 } catch (RemoteException re) { 269 Slog.e(LOG_TAG, "Error creating printer dicovery session.", re); 270 } 271 272 mHasPrinterDiscoverySession = true; 273 } 274 } 275 276 public void destroyPrinterDiscoverySession() { 277 mHandler.sendEmptyMessage(MyHandler.MSG_DESTROY_PRINTER_DISCOVERY_SESSION); 278 } 279 280 private void handleDestroyPrinterDiscoverySession() { 281 throwIfDestroyed(); 282 if (!isBound()) { 283 ensureBound(); 284 mPendingCommands.add(new Runnable() { 285 @Override 286 public void run() { 287 handleDestroyPrinterDiscoverySession(); 288 } 289 }); 290 } else { 291 if (DEBUG) { 292 Slog.i(LOG_TAG, "[user: " + mUserId + "] destroyPrinterDiscoverySession()"); 293 } 294 295 mHasPrinterDiscoverySession = false; 296 297 try { 298 mPrintService.destroyPrinterDiscoverySession(); 299 } catch (RemoteException re) { 300 Slog.e(LOG_TAG, "Error destroying printer dicovery session.", re); 301 } 302 303 // If the service has no print jobs and no active discovery 304 // session anymore we should disconnect from it. 305 if (!mHasActivePrintJobs) { 306 ensureUnbound(); 307 } 308 } 309 } 310 311 public void startPrinterDiscovery(List<PrinterId> priorityList) { 312 mHandler.obtainMessage(MyHandler.MSG_START_PRINTER_DISCOVERY, 313 priorityList).sendToTarget(); 314 } 315 316 private void handleStartPrinterDiscovery(final List<PrinterId> priorityList) { 317 throwIfDestroyed(); 318 if (!isBound()) { 319 ensureBound(); 320 mPendingCommands.add(new Runnable() { 321 @Override 322 public void run() { 323 handleStartPrinterDiscovery(priorityList); 324 } 325 }); 326 } else { 327 if (DEBUG) { 328 Slog.i(LOG_TAG, "[user: " + mUserId + "] startPrinterDiscovery()"); 329 } 330 try { 331 mPrintService.startPrinterDiscovery(priorityList); 332 } catch (RemoteException re) { 333 Slog.e(LOG_TAG, "Error starting printer dicovery.", re); 334 } 335 // Take a note that we are doing discovery. 336 mDiscoveryPriorityList = new ArrayList<PrinterId>(); 337 if (priorityList != null) { 338 mDiscoveryPriorityList.addAll(priorityList); 339 } 340 } 341 } 342 343 public void stopPrinterDiscovery() { 344 mHandler.sendEmptyMessage(MyHandler.MSG_STOP_PRINTER_DISCOVERY); 345 } 346 347 private void handleStopPrinterDiscovery() { 348 throwIfDestroyed(); 349 if (!isBound()) { 350 ensureBound(); 351 mPendingCommands.add(new Runnable() { 352 @Override 353 public void run() { 354 handleStopPrinterDiscovery(); 355 } 356 }); 357 } else { 358 if (DEBUG) { 359 Slog.i(LOG_TAG, "[user: " + mUserId + "] stopPrinterDiscovery()"); 360 } 361 // We are not doing discovery anymore. 362 mDiscoveryPriorityList = null; 363 try { 364 mPrintService.stopPrinterDiscovery(); 365 } catch (RemoteException re) { 366 Slog.e(LOG_TAG, "Error stopping printer dicovery.", re); 367 } 368 } 369 } 370 371 public void validatePrinters(List<PrinterId> printerIds) { 372 mHandler.obtainMessage(MyHandler.MSG_VALIDATE_PRINTERS, 373 printerIds).sendToTarget(); 374 } 375 376 private void handleValidatePrinters(final List<PrinterId> printerIds) { 377 throwIfDestroyed(); 378 if (!isBound()) { 379 ensureBound(); 380 mPendingCommands.add(new Runnable() { 381 @Override 382 public void run() { 383 handleValidatePrinters(printerIds); 384 } 385 }); 386 } else { 387 if (DEBUG) { 388 Slog.i(LOG_TAG, "[user: " + mUserId + "] validatePrinters()"); 389 } 390 try { 391 mPrintService.validatePrinters(printerIds); 392 } catch (RemoteException re) { 393 Slog.e(LOG_TAG, "Error requesting printers validation.", re); 394 } 395 } 396 } 397 398 public void startPrinterStateTracking(PrinterId printerId) { 399 mHandler.obtainMessage(MyHandler.MSG_START_PRINTER_STATE_TRACKING, 400 printerId).sendToTarget(); 401 } 402 403 private void handleStartPrinterStateTracking(final PrinterId printerId) { 404 throwIfDestroyed(); 405 if (!isBound()) { 406 ensureBound(); 407 mPendingCommands.add(new Runnable() { 408 @Override 409 public void run() { 410 handleStartPrinterStateTracking(printerId); 411 } 412 }); 413 } else { 414 if (DEBUG) { 415 Slog.i(LOG_TAG, "[user: " + mUserId + "] startPrinterTracking()"); 416 } 417 try { 418 mPrintService.startPrinterStateTracking(printerId); 419 } catch (RemoteException re) { 420 Slog.e(LOG_TAG, "Error requesting start printer tracking.", re); 421 } 422 // Take a note we are tracking the printer. 423 if (mTrackedPrinterList == null) { 424 mTrackedPrinterList = new ArrayList<PrinterId>(); 425 } 426 mTrackedPrinterList.add(printerId); 427 } 428 } 429 430 public void stopPrinterStateTracking(PrinterId printerId) { 431 mHandler.obtainMessage(MyHandler.MSG_STOP_PRINTER_STATE_TRACKING, 432 printerId).sendToTarget(); 433 } 434 435 private void handleStopPrinterStateTracking(final PrinterId printerId) { 436 throwIfDestroyed(); 437 if (!isBound()) { 438 ensureBound(); 439 mPendingCommands.add(new Runnable() { 440 @Override 441 public void run() { 442 handleStopPrinterStateTracking(printerId); 443 } 444 }); 445 } else { 446 if (DEBUG) { 447 Slog.i(LOG_TAG, "[user: " + mUserId + "] stopPrinterTracking()"); 448 } 449 // We are no longer tracking the printer. 450 mTrackedPrinterList.remove(printerId); 451 if (mTrackedPrinterList.isEmpty()) { 452 mTrackedPrinterList = null; 453 } 454 try { 455 mPrintService.stopPrinterStateTracking(printerId); 456 } catch (RemoteException re) { 457 Slog.e(LOG_TAG, "Error requesting stop printer tracking.", re); 458 } 459 } 460 } 461 462 private boolean isBound() { 463 return mPrintService != null; 464 } 465 466 private void ensureBound() { 467 if (isBound() || mBinding) { 468 return; 469 } 470 if (DEBUG) { 471 Slog.i(LOG_TAG, "[user: " + mUserId + "] ensureBound()"); 472 } 473 mBinding = true; 474 mContext.bindServiceAsUser(mIntent, mServiceConnection, 475 Context.BIND_AUTO_CREATE, new UserHandle(mUserId)); 476 } 477 478 private void ensureUnbound() { 479 if (!isBound() && !mBinding) { 480 return; 481 } 482 if (DEBUG) { 483 Slog.i(LOG_TAG, "[user: " + mUserId + "] ensureUnbound()"); 484 } 485 mBinding = false; 486 mPendingCommands.clear(); 487 mHasActivePrintJobs = false; 488 mHasPrinterDiscoverySession = false; 489 mDiscoveryPriorityList = null; 490 mTrackedPrinterList = null; 491 if (isBound()) { 492 try { 493 mPrintService.setClient(null); 494 } catch (RemoteException re) { 495 /* ignore */ 496 } 497 mPrintService.asBinder().unlinkToDeath(this, 0); 498 mPrintService = null; 499 mContext.unbindService(mServiceConnection); 500 } 501 } 502 503 private void throwIfDestroyed() { 504 if (mDestroyed) { 505 throw new IllegalStateException("Cannot interact with a destroyed service"); 506 } 507 } 508 509 private class RemoteServiceConneciton implements ServiceConnection { 510 @Override 511 public void onServiceConnected(ComponentName name, IBinder service) { 512 if (mDestroyed || !mBinding) { 513 return; 514 } 515 mBinding = false; 516 mPrintService = IPrintService.Stub.asInterface(service); 517 try { 518 service.linkToDeath(RemotePrintService.this, 0); 519 } catch (RemoteException re) { 520 handleBinderDied(); 521 return; 522 } 523 try { 524 mPrintService.setClient(mPrintServiceClient); 525 } catch (RemoteException re) { 526 Slog.e(LOG_TAG, "Error setting client for: " + service, re); 527 handleBinderDied(); 528 return; 529 } 530 // If there is a session, then the service died after creating 531 // a session. Hence, recreate the session. 532 if (mHasPrinterDiscoverySession) { 533 handleCreatePrinterDiscoverySession(); 534 } 535 // If there is a priority list, then the service died during 536 // discovery and is restarted. Hence, start discovery. 537 if (mDiscoveryPriorityList != null) { 538 handleStartPrinterDiscovery(mDiscoveryPriorityList); 539 } 540 // If there is a tracked printer list, then the service died 541 // during discovery and is restarted. Hence, start tracking. 542 if (mTrackedPrinterList != null) { 543 final int trackedPrinterCount = mTrackedPrinterList.size(); 544 for (int i = 0; i < trackedPrinterCount; i++) { 545 handleStartPrinterStateTracking(mTrackedPrinterList.get(i)); 546 } 547 } 548 // Finally, do all the pending work. 549 final int pendingCommandCount = mPendingCommands.size(); 550 for (int i = 0; i < pendingCommandCount; i++) { 551 Runnable pendingCommand = mPendingCommands.get(i); 552 pendingCommand.run(); 553 } 554 mPendingCommands.clear(); 555 } 556 557 @Override 558 public void onServiceDisconnected(ComponentName name) { 559 mBinding = true; 560 } 561 } 562 563 private final class MyHandler extends Handler { 564 public static final int MSG_CREATE_PRINTER_DISCOVERY_SESSION = 1; 565 public static final int MSG_DESTROY_PRINTER_DISCOVERY_SESSION = 2; 566 public static final int MSG_START_PRINTER_DISCOVERY = 3; 567 public static final int MSG_STOP_PRINTER_DISCOVERY = 4; 568 public static final int MSG_VALIDATE_PRINTERS = 5; 569 public static final int MSG_START_PRINTER_STATE_TRACKING = 6; 570 public static final int MSG_STOP_PRINTER_STATE_TRACKING = 7; 571 public static final int MSG_ON_ALL_PRINT_JOBS_HANDLED = 8; 572 public static final int MSG_ON_REQUEST_CANCEL_PRINT_JOB = 9; 573 public static final int MSG_ON_PRINT_JOB_QUEUED = 10; 574 public static final int MSG_DESTROY = 11; 575 public static final int MSG_BINDER_DIED = 12; 576 577 public MyHandler(Looper looper) { 578 super(looper, null, false); 579 } 580 581 @Override 582 @SuppressWarnings("unchecked") 583 public void handleMessage(Message message) { 584 switch (message.what) { 585 case MSG_CREATE_PRINTER_DISCOVERY_SESSION: { 586 handleCreatePrinterDiscoverySession(); 587 } break; 588 589 case MSG_DESTROY_PRINTER_DISCOVERY_SESSION: { 590 handleDestroyPrinterDiscoverySession(); 591 } break; 592 593 case MSG_START_PRINTER_DISCOVERY: { 594 List<PrinterId> priorityList = (ArrayList<PrinterId>) message.obj; 595 handleStartPrinterDiscovery(priorityList); 596 } break; 597 598 case MSG_STOP_PRINTER_DISCOVERY: { 599 handleStopPrinterDiscovery(); 600 } break; 601 602 case MSG_VALIDATE_PRINTERS: { 603 List<PrinterId> printerIds = (List<PrinterId>) message.obj; 604 handleValidatePrinters(printerIds); 605 } break; 606 607 case MSG_START_PRINTER_STATE_TRACKING: { 608 PrinterId printerId = (PrinterId) message.obj; 609 handleStartPrinterStateTracking(printerId); 610 } break; 611 612 case MSG_STOP_PRINTER_STATE_TRACKING: { 613 PrinterId printerId = (PrinterId) message.obj; 614 handleStopPrinterStateTracking(printerId); 615 } break; 616 617 case MSG_ON_ALL_PRINT_JOBS_HANDLED: { 618 handleOnAllPrintJobsHandled(); 619 } break; 620 621 case MSG_ON_REQUEST_CANCEL_PRINT_JOB: { 622 PrintJobInfo printJob = (PrintJobInfo) message.obj; 623 handleRequestCancelPrintJob(printJob); 624 } break; 625 626 case MSG_ON_PRINT_JOB_QUEUED: { 627 PrintJobInfo printJob = (PrintJobInfo) message.obj; 628 handleOnPrintJobQueued(printJob); 629 } break; 630 631 case MSG_DESTROY: { 632 handleDestroy(); 633 } break; 634 635 case MSG_BINDER_DIED: { 636 handleBinderDied(); 637 } break; 638 } 639 } 640 } 641 642 private static final class RemotePrintServiceClient extends IPrintServiceClient.Stub { 643 private final WeakReference<RemotePrintService> mWeakService; 644 645 public RemotePrintServiceClient(RemotePrintService service) { 646 mWeakService = new WeakReference<RemotePrintService>(service); 647 } 648 649 @Override 650 public List<PrintJobInfo> getPrintJobInfos() { 651 RemotePrintService service = mWeakService.get(); 652 if (service != null) { 653 final long identity = Binder.clearCallingIdentity(); 654 try { 655 return service.mSpooler.getPrintJobInfos(service.mComponentName, 656 PrintJobInfo.STATE_ANY_VISIBLE_TO_CLIENTS, PrintManager.APP_ID_ANY); 657 } finally { 658 Binder.restoreCallingIdentity(identity); 659 } 660 } 661 return null; 662 } 663 664 @Override 665 public PrintJobInfo getPrintJobInfo(int printJobId) { 666 RemotePrintService service = mWeakService.get(); 667 if (service != null) { 668 final long identity = Binder.clearCallingIdentity(); 669 try { 670 return service.mSpooler.getPrintJobInfo(printJobId, 671 PrintManager.APP_ID_ANY); 672 } finally { 673 Binder.restoreCallingIdentity(identity); 674 } 675 } 676 return null; 677 } 678 679 @Override 680 public boolean setPrintJobState(int printJobId, int state, String error) { 681 RemotePrintService service = mWeakService.get(); 682 if (service != null) { 683 final long identity = Binder.clearCallingIdentity(); 684 try { 685 return service.mSpooler.setPrintJobState(printJobId, state, error); 686 } finally { 687 Binder.restoreCallingIdentity(identity); 688 } 689 } 690 return false; 691 } 692 693 @Override 694 public boolean setPrintJobTag(int printJobId, String tag) { 695 RemotePrintService service = mWeakService.get(); 696 if (service != null) { 697 final long identity = Binder.clearCallingIdentity(); 698 try { 699 return service.mSpooler.setPrintJobTag(printJobId, tag); 700 } finally { 701 Binder.restoreCallingIdentity(identity); 702 } 703 } 704 return false; 705 } 706 707 @Override 708 public void writePrintJobData(ParcelFileDescriptor fd, int printJobId) { 709 RemotePrintService service = mWeakService.get(); 710 if (service != null) { 711 final long identity = Binder.clearCallingIdentity(); 712 try { 713 service.mSpooler.writePrintJobData(fd, printJobId); 714 } finally { 715 Binder.restoreCallingIdentity(identity); 716 } 717 } 718 } 719 720 @Override 721 public void onPrintersAdded(List<PrinterInfo> printers) { 722 RemotePrintService service = mWeakService.get(); 723 if (service != null) { 724 throwIfPrinterIdsForPrinterInfoTampered(service.mComponentName, printers); 725 final long identity = Binder.clearCallingIdentity(); 726 try { 727 service.mCallbacks.onPrintersAdded(printers); 728 } finally { 729 Binder.restoreCallingIdentity(identity); 730 } 731 } 732 } 733 734 @Override 735 public void onPrintersRemoved(List<PrinterId> printerIds) { 736 RemotePrintService service = mWeakService.get(); 737 if (service != null) { 738 throwIfPrinterIdsTampered(service.mComponentName, printerIds); 739 final long identity = Binder.clearCallingIdentity(); 740 try { 741 service.mCallbacks.onPrintersRemoved(printerIds); 742 } finally { 743 Binder.restoreCallingIdentity(identity); 744 } 745 } 746 } 747 748 private void throwIfPrinterIdsForPrinterInfoTampered(ComponentName serviceName, 749 List<PrinterInfo> printerInfos) { 750 final int printerInfoCount = printerInfos.size(); 751 for (int i = 0; i < printerInfoCount; i++) { 752 PrinterId printerId = printerInfos.get(i).getId(); 753 throwIfPrinterIdTampered(serviceName, printerId); 754 } 755 } 756 757 private void throwIfPrinterIdsTampered(ComponentName serviceName, 758 List<PrinterId> printerIds) { 759 final int printerIdCount = printerIds.size(); 760 for (int i = 0; i < printerIdCount; i++) { 761 PrinterId printerId = printerIds.get(i); 762 throwIfPrinterIdTampered(serviceName, printerId); 763 } 764 } 765 766 private void throwIfPrinterIdTampered(ComponentName serviceName, PrinterId printerId) { 767 if (printerId == null || printerId.getServiceName() == null 768 || !printerId.getServiceName().equals(serviceName)) { 769 throw new IllegalArgumentException("Invalid printer id: " + printerId); 770 } 771 } 772 } 773} 774