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 static android.content.pm.PackageManager.GET_SERVICES; 20import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING; 21 22import android.Manifest; 23import android.annotation.NonNull; 24import android.app.ActivityManager; 25import android.app.ActivityManagerNative; 26import android.content.ComponentName; 27import android.content.Context; 28import android.content.Intent; 29import android.content.pm.PackageManager; 30import android.content.pm.ResolveInfo; 31import android.content.pm.UserInfo; 32import android.database.ContentObserver; 33import android.graphics.drawable.Icon; 34import android.net.Uri; 35import android.os.Binder; 36import android.os.Bundle; 37import android.os.Process; 38import android.os.RemoteException; 39import android.os.UserHandle; 40import android.os.UserManager; 41import android.print.IPrintDocumentAdapter; 42import android.print.IPrintJobStateChangeListener; 43import android.print.IPrintManager; 44import android.printservice.recommendation.IRecommendationsChangeListener; 45import android.print.IPrintServicesChangeListener; 46import android.print.IPrinterDiscoveryObserver; 47import android.print.PrintAttributes; 48import android.print.PrintJobId; 49import android.print.PrintJobInfo; 50import android.print.PrintManager; 51import android.printservice.recommendation.RecommendationInfo; 52import android.print.PrinterId; 53import android.printservice.PrintServiceInfo; 54import android.provider.Settings; 55import android.util.Log; 56import android.util.SparseArray; 57 58import com.android.internal.content.PackageMonitor; 59import com.android.internal.os.BackgroundThread; 60import com.android.internal.util.Preconditions; 61import com.android.server.SystemService; 62 63import java.io.FileDescriptor; 64import java.io.PrintWriter; 65import java.util.Iterator; 66import java.util.List; 67 68/** 69 * SystemService wrapper for the PrintManager implementation. Publishes 70 * Context.PRINT_SERVICE. 71 * PrintManager implementation is contained within. 72 */ 73public final class PrintManagerService extends SystemService { 74 private static final String LOG_TAG = "PrintManagerService"; 75 76 private final PrintManagerImpl mPrintManagerImpl; 77 78 public PrintManagerService(Context context) { 79 super(context); 80 mPrintManagerImpl = new PrintManagerImpl(context); 81 } 82 83 @Override 84 public void onStart() { 85 publishBinderService(Context.PRINT_SERVICE, mPrintManagerImpl); 86 } 87 88 @Override 89 public void onUnlockUser(int userHandle) { 90 mPrintManagerImpl.handleUserUnlocked(userHandle); 91 } 92 93 @Override 94 public void onStopUser(int userHandle) { 95 mPrintManagerImpl.handleUserStopped(userHandle); 96 } 97 98 class PrintManagerImpl extends IPrintManager.Stub { 99 private static final int BACKGROUND_USER_ID = -10; 100 101 private final Object mLock = new Object(); 102 103 private final Context mContext; 104 105 private final UserManager mUserManager; 106 107 private final SparseArray<UserState> mUserStates = new SparseArray<>(); 108 109 PrintManagerImpl(Context context) { 110 mContext = context; 111 mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); 112 registerContentObservers(); 113 registerBroadcastReceivers(); 114 } 115 116 @Override 117 public Bundle print(String printJobName, IPrintDocumentAdapter adapter, 118 PrintAttributes attributes, String packageName, int appId, int userId) { 119 printJobName = Preconditions.checkStringNotEmpty(printJobName); 120 adapter = Preconditions.checkNotNull(adapter); 121 packageName = Preconditions.checkStringNotEmpty(packageName); 122 123 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 124 final int resolvedAppId; 125 final UserState userState; 126 final String resolvedPackageName; 127 synchronized (mLock) { 128 // Only the current group members can start new print jobs. 129 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { 130 return null; 131 } 132 resolvedAppId = resolveCallingAppEnforcingPermissions(appId); 133 resolvedPackageName = resolveCallingPackageNameEnforcingSecurity(packageName); 134 userState = getOrCreateUserStateLocked(resolvedUserId, false); 135 } 136 final long identity = Binder.clearCallingIdentity(); 137 try { 138 return userState.print(printJobName, adapter, attributes, 139 resolvedPackageName, resolvedAppId); 140 } finally { 141 Binder.restoreCallingIdentity(identity); 142 } 143 } 144 145 @Override 146 public List<PrintJobInfo> getPrintJobInfos(int appId, int userId) { 147 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 148 final int resolvedAppId; 149 final UserState userState; 150 synchronized (mLock) { 151 // Only the current group members can query for state of print jobs. 152 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { 153 return null; 154 } 155 resolvedAppId = resolveCallingAppEnforcingPermissions(appId); 156 userState = getOrCreateUserStateLocked(resolvedUserId, false); 157 } 158 final long identity = Binder.clearCallingIdentity(); 159 try { 160 return userState.getPrintJobInfos(resolvedAppId); 161 } finally { 162 Binder.restoreCallingIdentity(identity); 163 } 164 } 165 166 @Override 167 public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId, int userId) { 168 if (printJobId == null) { 169 return null; 170 } 171 172 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 173 final int resolvedAppId; 174 final UserState userState; 175 synchronized (mLock) { 176 // Only the current group members can query for state of a print job. 177 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { 178 return null; 179 } 180 resolvedAppId = resolveCallingAppEnforcingPermissions(appId); 181 userState = getOrCreateUserStateLocked(resolvedUserId, false); 182 } 183 final long identity = Binder.clearCallingIdentity(); 184 try { 185 return userState.getPrintJobInfo(printJobId, resolvedAppId); 186 } finally { 187 Binder.restoreCallingIdentity(identity); 188 } 189 } 190 191 @Override 192 public Icon getCustomPrinterIcon(PrinterId printerId, int userId) { 193 printerId = Preconditions.checkNotNull(printerId); 194 195 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 196 final UserState userState; 197 synchronized (mLock) { 198 // Only the current group members can get the printer icons. 199 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { 200 return null; 201 } 202 userState = getOrCreateUserStateLocked(resolvedUserId, false); 203 } 204 final long identity = Binder.clearCallingIdentity(); 205 try { 206 return userState.getCustomPrinterIcon(printerId); 207 } finally { 208 Binder.restoreCallingIdentity(identity); 209 } 210 } 211 212 @Override 213 public void cancelPrintJob(PrintJobId printJobId, int appId, int userId) { 214 if (printJobId == null) { 215 return; 216 } 217 218 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 219 final int resolvedAppId; 220 final UserState userState; 221 synchronized (mLock) { 222 // Only the current group members can cancel a print job. 223 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { 224 return; 225 } 226 resolvedAppId = resolveCallingAppEnforcingPermissions(appId); 227 userState = getOrCreateUserStateLocked(resolvedUserId, false); 228 } 229 final long identity = Binder.clearCallingIdentity(); 230 try { 231 userState.cancelPrintJob(printJobId, resolvedAppId); 232 } finally { 233 Binder.restoreCallingIdentity(identity); 234 } 235 } 236 237 @Override 238 public void restartPrintJob(PrintJobId printJobId, int appId, int userId) { 239 if (printJobId == null) { 240 return; 241 } 242 243 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 244 final int resolvedAppId; 245 final UserState userState; 246 synchronized (mLock) { 247 // Only the current group members can restart a print job. 248 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { 249 return; 250 } 251 resolvedAppId = resolveCallingAppEnforcingPermissions(appId); 252 userState = getOrCreateUserStateLocked(resolvedUserId, false); 253 } 254 final long identity = Binder.clearCallingIdentity(); 255 try { 256 userState.restartPrintJob(printJobId, resolvedAppId); 257 } finally { 258 Binder.restoreCallingIdentity(identity); 259 } 260 } 261 262 @Override 263 public List<PrintServiceInfo> getPrintServices(int selectionFlags, int userId) { 264 Preconditions.checkFlagsArgument(selectionFlags, 265 PrintManager.DISABLED_SERVICES | PrintManager.ENABLED_SERVICES); 266 267 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 268 final UserState userState; 269 synchronized (mLock) { 270 // Only the current group members can get print services. 271 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { 272 return null; 273 } 274 userState = getOrCreateUserStateLocked(resolvedUserId, false); 275 } 276 final long identity = Binder.clearCallingIdentity(); 277 try { 278 return userState.getPrintServices(selectionFlags); 279 } finally { 280 Binder.restoreCallingIdentity(identity); 281 } 282 } 283 284 @Override 285 public void setPrintServiceEnabled(ComponentName service, boolean isEnabled, int userId) { 286 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 287 final int appId = UserHandle.getAppId(Binder.getCallingUid()); 288 289 try { 290 if (appId != Process.SYSTEM_UID && appId != UserHandle.getAppId( 291 mContext.getPackageManager().getPackageUidAsUser( 292 PrintManager.PRINT_SPOOLER_PACKAGE_NAME, resolvedUserId))) { 293 throw new SecurityException("Only system and print spooler can call this"); 294 } 295 } catch (PackageManager.NameNotFoundException e) { 296 Log.e(LOG_TAG, "Could not verify caller", e); 297 return; 298 } 299 300 service = Preconditions.checkNotNull(service); 301 302 final UserState userState; 303 synchronized (mLock) { 304 // Only the current group members can enable / disable services. 305 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { 306 return; 307 } 308 userState = getOrCreateUserStateLocked(resolvedUserId, false); 309 } 310 final long identity = Binder.clearCallingIdentity(); 311 try { 312 userState.setPrintServiceEnabled(service, isEnabled); 313 } finally { 314 Binder.restoreCallingIdentity(identity); 315 } 316 } 317 318 @Override 319 public List<RecommendationInfo> getPrintServiceRecommendations(int userId) { 320 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 321 final UserState userState; 322 synchronized (mLock) { 323 // Only the current group members can get print service recommendations. 324 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { 325 return null; 326 } 327 userState = getOrCreateUserStateLocked(resolvedUserId, false); 328 } 329 final long identity = Binder.clearCallingIdentity(); 330 try { 331 return userState.getPrintServiceRecommendations(); 332 } finally { 333 Binder.restoreCallingIdentity(identity); 334 } 335 } 336 337 @Override 338 public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer, 339 int userId) { 340 observer = Preconditions.checkNotNull(observer); 341 342 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 343 final UserState userState; 344 synchronized (mLock) { 345 // Only the current group members can create a discovery session. 346 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { 347 return; 348 } 349 userState = getOrCreateUserStateLocked(resolvedUserId, false); 350 } 351 final long identity = Binder.clearCallingIdentity(); 352 try { 353 userState.createPrinterDiscoverySession(observer); 354 } finally { 355 Binder.restoreCallingIdentity(identity); 356 } 357 } 358 359 @Override 360 public void destroyPrinterDiscoverySession(IPrinterDiscoveryObserver observer, 361 int userId) { 362 observer = Preconditions.checkNotNull(observer); 363 364 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 365 final UserState userState; 366 synchronized (mLock) { 367 // Only the current group members can destroy a discovery session. 368 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { 369 return; 370 } 371 userState = getOrCreateUserStateLocked(resolvedUserId, false); 372 } 373 final long identity = Binder.clearCallingIdentity(); 374 try { 375 userState.destroyPrinterDiscoverySession(observer); 376 } finally { 377 Binder.restoreCallingIdentity(identity); 378 } 379 } 380 381 @Override 382 public void startPrinterDiscovery(IPrinterDiscoveryObserver observer, 383 List<PrinterId> priorityList, int userId) { 384 observer = Preconditions.checkNotNull(observer); 385 if (priorityList != null) { 386 priorityList = Preconditions.checkCollectionElementsNotNull(priorityList, 387 "PrinterId"); 388 } 389 390 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 391 final UserState userState; 392 synchronized (mLock) { 393 // Only the current group members can start discovery. 394 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { 395 return; 396 } 397 userState = getOrCreateUserStateLocked(resolvedUserId, false); 398 } 399 final long identity = Binder.clearCallingIdentity(); 400 try { 401 userState.startPrinterDiscovery(observer, priorityList); 402 } finally { 403 Binder.restoreCallingIdentity(identity); 404 } 405 } 406 407 @Override 408 public void stopPrinterDiscovery(IPrinterDiscoveryObserver observer, int userId) { 409 observer = Preconditions.checkNotNull(observer); 410 411 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 412 final UserState userState; 413 synchronized (mLock) { 414 // Only the current group members can stop discovery. 415 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { 416 return; 417 } 418 userState = getOrCreateUserStateLocked(resolvedUserId, false); 419 } 420 final long identity = Binder.clearCallingIdentity(); 421 try { 422 userState.stopPrinterDiscovery(observer); 423 } finally { 424 Binder.restoreCallingIdentity(identity); 425 } 426 } 427 428 @Override 429 public void validatePrinters(List<PrinterId> printerIds, int userId) { 430 printerIds = Preconditions.checkCollectionElementsNotNull(printerIds, "PrinterId"); 431 432 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 433 final UserState userState; 434 synchronized (mLock) { 435 // Only the current group members can validate printers. 436 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { 437 return; 438 } 439 userState = getOrCreateUserStateLocked(resolvedUserId, false); 440 } 441 final long identity = Binder.clearCallingIdentity(); 442 try { 443 userState.validatePrinters(printerIds); 444 } finally { 445 Binder.restoreCallingIdentity(identity); 446 } 447 } 448 449 @Override 450 public void startPrinterStateTracking(PrinterId printerId, int userId) { 451 printerId = Preconditions.checkNotNull(printerId); 452 453 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 454 final UserState userState; 455 synchronized (mLock) { 456 // Only the current group members can start printer tracking. 457 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { 458 return; 459 } 460 userState = getOrCreateUserStateLocked(resolvedUserId, false); 461 } 462 final long identity = Binder.clearCallingIdentity(); 463 try { 464 userState.startPrinterStateTracking(printerId); 465 } finally { 466 Binder.restoreCallingIdentity(identity); 467 } 468 } 469 470 @Override 471 public void stopPrinterStateTracking(PrinterId printerId, int userId) { 472 printerId = Preconditions.checkNotNull(printerId); 473 474 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 475 final UserState userState; 476 synchronized (mLock) { 477 // Only the current group members can stop printer tracking. 478 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { 479 return; 480 } 481 userState = getOrCreateUserStateLocked(resolvedUserId, false); 482 } 483 final long identity = Binder.clearCallingIdentity(); 484 try { 485 userState.stopPrinterStateTracking(printerId); 486 } finally { 487 Binder.restoreCallingIdentity(identity); 488 } 489 } 490 491 @Override 492 public void addPrintJobStateChangeListener(IPrintJobStateChangeListener listener, 493 int appId, int userId) throws RemoteException { 494 listener = Preconditions.checkNotNull(listener); 495 496 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 497 final int resolvedAppId; 498 final UserState userState; 499 synchronized (mLock) { 500 // Only the current group members can add a print job listener. 501 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { 502 return; 503 } 504 resolvedAppId = resolveCallingAppEnforcingPermissions(appId); 505 userState = getOrCreateUserStateLocked(resolvedUserId, false); 506 } 507 final long identity = Binder.clearCallingIdentity(); 508 try { 509 userState.addPrintJobStateChangeListener(listener, resolvedAppId); 510 } finally { 511 Binder.restoreCallingIdentity(identity); 512 } 513 } 514 515 @Override 516 public void removePrintJobStateChangeListener(IPrintJobStateChangeListener listener, 517 int userId) { 518 listener = Preconditions.checkNotNull(listener); 519 520 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 521 final UserState userState; 522 synchronized (mLock) { 523 // Only the current group members can remove a print job listener. 524 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { 525 return; 526 } 527 userState = getOrCreateUserStateLocked(resolvedUserId, false); 528 } 529 final long identity = Binder.clearCallingIdentity(); 530 try { 531 userState.removePrintJobStateChangeListener(listener); 532 } finally { 533 Binder.restoreCallingIdentity(identity); 534 } 535 } 536 537 @Override 538 public void addPrintServicesChangeListener(IPrintServicesChangeListener listener, 539 int userId) throws RemoteException { 540 listener = Preconditions.checkNotNull(listener); 541 542 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 543 final UserState userState; 544 synchronized (mLock) { 545 // Only the current group members can add a print services listener. 546 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { 547 return; 548 } 549 userState = getOrCreateUserStateLocked(resolvedUserId, false); 550 } 551 final long identity = Binder.clearCallingIdentity(); 552 try { 553 userState.addPrintServicesChangeListener(listener); 554 } finally { 555 Binder.restoreCallingIdentity(identity); 556 } 557 } 558 559 @Override 560 public void removePrintServicesChangeListener(IPrintServicesChangeListener listener, 561 int userId) { 562 listener = Preconditions.checkNotNull(listener); 563 564 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 565 final UserState userState; 566 synchronized (mLock) { 567 // Only the current group members can remove a print services change listener. 568 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { 569 return; 570 } 571 userState = getOrCreateUserStateLocked(resolvedUserId, false); 572 } 573 final long identity = Binder.clearCallingIdentity(); 574 try { 575 userState.removePrintServicesChangeListener(listener); 576 } finally { 577 Binder.restoreCallingIdentity(identity); 578 } 579 } 580 581 @Override 582 public void addPrintServiceRecommendationsChangeListener( 583 IRecommendationsChangeListener listener, int userId) 584 throws RemoteException { 585 listener = Preconditions.checkNotNull(listener); 586 587 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 588 final UserState userState; 589 synchronized (mLock) { 590 // Only the current group members can add a print service recommendations listener. 591 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { 592 return; 593 } 594 userState = getOrCreateUserStateLocked(resolvedUserId, false); 595 } 596 final long identity = Binder.clearCallingIdentity(); 597 try { 598 userState.addPrintServiceRecommendationsChangeListener(listener); 599 } finally { 600 Binder.restoreCallingIdentity(identity); 601 } 602 } 603 604 @Override 605 public void removePrintServiceRecommendationsChangeListener( 606 IRecommendationsChangeListener listener, int userId) { 607 listener = Preconditions.checkNotNull(listener); 608 609 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 610 final UserState userState; 611 synchronized (mLock) { 612 // Only the current group members can remove a print service recommendations 613 // listener. 614 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) { 615 return; 616 } 617 userState = getOrCreateUserStateLocked(resolvedUserId, false); 618 } 619 final long identity = Binder.clearCallingIdentity(); 620 try { 621 userState.removePrintServiceRecommendationsChangeListener(listener); 622 } finally { 623 Binder.restoreCallingIdentity(identity); 624 } 625 } 626 627 @Override 628 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 629 fd = Preconditions.checkNotNull(fd); 630 pw = Preconditions.checkNotNull(pw); 631 632 if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) 633 != PackageManager.PERMISSION_GRANTED) { 634 pw.println("Permission Denial: can't dump PrintManager from from pid=" 635 + Binder.getCallingPid() 636 + ", uid=" + Binder.getCallingUid()); 637 return; 638 } 639 640 synchronized (mLock) { 641 final long identity = Binder.clearCallingIdentity(); 642 try { 643 pw.println("PRINT MANAGER STATE (dumpsys print)"); 644 final int userStateCount = mUserStates.size(); 645 for (int i = 0; i < userStateCount; i++) { 646 UserState userState = mUserStates.valueAt(i); 647 userState.dump(fd, pw, ""); 648 pw.println(); 649 } 650 } finally { 651 Binder.restoreCallingIdentity(identity); 652 } 653 } 654 } 655 656 private void registerContentObservers() { 657 final Uri enabledPrintServicesUri = Settings.Secure.getUriFor( 658 Settings.Secure.DISABLED_PRINT_SERVICES); 659 ContentObserver observer = new ContentObserver(BackgroundThread.getHandler()) { 660 @Override 661 public void onChange(boolean selfChange, Uri uri, int userId) { 662 if (enabledPrintServicesUri.equals(uri)) { 663 synchronized (mLock) { 664 final int userCount = mUserStates.size(); 665 for (int i = 0; i < userCount; i++) { 666 if (userId == UserHandle.USER_ALL 667 || userId == mUserStates.keyAt(i)) { 668 mUserStates.valueAt(i).updateIfNeededLocked(); 669 } 670 } 671 } 672 } 673 } 674 }; 675 676 mContext.getContentResolver().registerContentObserver(enabledPrintServicesUri, 677 false, observer, UserHandle.USER_ALL); 678 } 679 680 private void registerBroadcastReceivers() { 681 PackageMonitor monitor = new PackageMonitor() { 682 /** 683 * Checks if the package contains a print service. 684 * 685 * @param packageName The name of the package 686 * 687 * @return true iff the package contains a print service 688 */ 689 private boolean hasPrintService(String packageName) { 690 Intent intent = new Intent(android.printservice.PrintService.SERVICE_INTERFACE); 691 intent.setPackage(packageName); 692 693 List<ResolveInfo> installedServices = mContext.getPackageManager() 694 .queryIntentServicesAsUser(intent, 695 GET_SERVICES | MATCH_DEBUG_TRIAGED_MISSING, 696 getChangingUserId()); 697 698 return installedServices != null && !installedServices.isEmpty(); 699 } 700 701 /** 702 * Checks if there is a print service currently registered for this package. 703 * 704 * @param userState The userstate for the current user 705 * @param packageName The name of the package 706 * 707 * @return true iff the package contained (and might still contain) a print service 708 */ 709 private boolean hadPrintService(@NonNull UserState userState, String packageName) { 710 List<PrintServiceInfo> installedServices = userState 711 .getPrintServices(PrintManager.ALL_SERVICES); 712 713 if (installedServices == null) { 714 return false; 715 } 716 717 final int numInstalledServices = installedServices.size(); 718 for (int i = 0; i < numInstalledServices; i++) { 719 if (installedServices.get(i).getResolveInfo().serviceInfo.packageName 720 .equals(packageName)) { 721 return true; 722 } 723 } 724 725 return false; 726 } 727 728 @Override 729 public void onPackageModified(String packageName) { 730 if (!mUserManager.isUserUnlockingOrUnlocked(getChangingUserId())) return; 731 UserState userState = getOrCreateUserStateLocked(getChangingUserId(), false); 732 733 synchronized (mLock) { 734 if (hadPrintService(userState, packageName) 735 || hasPrintService(packageName)) { 736 userState.updateIfNeededLocked(); 737 } 738 } 739 740 userState.prunePrintServices(); 741 } 742 743 @Override 744 public void onPackageRemoved(String packageName, int uid) { 745 if (!mUserManager.isUserUnlockingOrUnlocked(getChangingUserId())) return; 746 UserState userState = getOrCreateUserStateLocked(getChangingUserId(), false); 747 748 synchronized (mLock) { 749 if (hadPrintService(userState, packageName)) { 750 userState.updateIfNeededLocked(); 751 } 752 } 753 754 userState.prunePrintServices(); 755 } 756 757 @Override 758 public boolean onHandleForceStop(Intent intent, String[] stoppedPackages, 759 int uid, boolean doit) { 760 if (!mUserManager.isUserUnlockingOrUnlocked(getChangingUserId())) return false; 761 synchronized (mLock) { 762 // A background user/profile's print jobs are running but there is 763 // no UI shown. Hence, if the packages of such a user change we need 764 // to handle it as the change may affect ongoing print jobs. 765 UserState userState = getOrCreateUserStateLocked(getChangingUserId(), 766 false); 767 boolean stoppedSomePackages = false; 768 769 List<PrintServiceInfo> enabledServices = userState 770 .getPrintServices(PrintManager.ENABLED_SERVICES); 771 if (enabledServices == null) { 772 return false; 773 } 774 775 Iterator<PrintServiceInfo> iterator = enabledServices.iterator(); 776 while (iterator.hasNext()) { 777 ComponentName componentName = iterator.next().getComponentName(); 778 String componentPackage = componentName.getPackageName(); 779 for (String stoppedPackage : stoppedPackages) { 780 if (componentPackage.equals(stoppedPackage)) { 781 if (!doit) { 782 return true; 783 } 784 stoppedSomePackages = true; 785 break; 786 } 787 } 788 } 789 if (stoppedSomePackages) { 790 userState.updateIfNeededLocked(); 791 } 792 return false; 793 } 794 } 795 796 @Override 797 public void onPackageAdded(String packageName, int uid) { 798 if (!mUserManager.isUserUnlockingOrUnlocked(getChangingUserId())) return; 799 synchronized (mLock) { 800 if (hasPrintService(packageName)) { 801 UserState userState = getOrCreateUserStateLocked(getChangingUserId(), 802 false); 803 userState.updateIfNeededLocked(); 804 } 805 } 806 } 807 }; 808 809 // package changes 810 monitor.register(mContext, BackgroundThread.getHandler().getLooper(), 811 UserHandle.ALL, true); 812 } 813 814 private UserState getOrCreateUserStateLocked(int userId, boolean lowPriority) { 815 if (!mUserManager.isUserUnlockingOrUnlocked(userId)) { 816 throw new IllegalStateException( 817 "User " + userId + " must be unlocked for printing to be available"); 818 } 819 820 UserState userState = mUserStates.get(userId); 821 if (userState == null) { 822 userState = new UserState(mContext, userId, mLock, lowPriority); 823 mUserStates.put(userId, userState); 824 } 825 826 if (!lowPriority) { 827 userState.increasePriority(); 828 } 829 830 return userState; 831 } 832 833 private void handleUserUnlocked(final int userId) { 834 // This code will touch the remote print spooler which 835 // must be called off the main thread, so post the work. 836 BackgroundThread.getHandler().post(new Runnable() { 837 @Override 838 public void run() { 839 if (!mUserManager.isUserUnlockingOrUnlocked(userId)) return; 840 841 UserState userState; 842 synchronized (mLock) { 843 userState = getOrCreateUserStateLocked(userId, true); 844 userState.updateIfNeededLocked(); 845 } 846 // This is the first time we switch to this user after boot, so 847 // now is the time to remove obsolete print jobs since they 848 // are from the last boot and no application would query them. 849 userState.removeObsoletePrintJobs(); 850 } 851 }); 852 } 853 854 private void handleUserStopped(final int userId) { 855 // This code will touch the remote print spooler which 856 // must be called off the main thread, so post the work. 857 BackgroundThread.getHandler().post(new Runnable() { 858 @Override 859 public void run() { 860 synchronized (mLock) { 861 UserState userState = mUserStates.get(userId); 862 if (userState != null) { 863 userState.destroyLocked(); 864 mUserStates.remove(userId); 865 } 866 } 867 } 868 }); 869 } 870 871 private int resolveCallingProfileParentLocked(int userId) { 872 if (userId != getCurrentUserId()) { 873 final long identity = Binder.clearCallingIdentity(); 874 try { 875 UserInfo parent = mUserManager.getProfileParent(userId); 876 if (parent != null) { 877 return parent.getUserHandle().getIdentifier(); 878 } else { 879 return BACKGROUND_USER_ID; 880 } 881 } finally { 882 Binder.restoreCallingIdentity(identity); 883 } 884 } 885 return userId; 886 } 887 888 private int resolveCallingAppEnforcingPermissions(int appId) { 889 final int callingUid = Binder.getCallingUid(); 890 if (callingUid == 0 || callingUid == Process.SYSTEM_UID 891 || callingUid == Process.SHELL_UID) { 892 return appId; 893 } 894 final int callingAppId = UserHandle.getAppId(callingUid); 895 if (appId == callingAppId) { 896 return appId; 897 } 898 if (mContext.checkCallingPermission( 899 "com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS") 900 != PackageManager.PERMISSION_GRANTED) { 901 throw new SecurityException("Call from app " + callingAppId + " as app " 902 + appId + " without com.android.printspooler.permission" 903 + ".ACCESS_ALL_PRINT_JOBS"); 904 } 905 return appId; 906 } 907 908 private int resolveCallingUserEnforcingPermissions(int userId) { 909 try { 910 return ActivityManagerNative.getDefault().handleIncomingUser(Binder.getCallingPid(), 911 Binder.getCallingUid(), userId, true, true, "", null); 912 } catch (RemoteException re) { 913 // Shouldn't happen, local. 914 } 915 return userId; 916 } 917 918 private @NonNull String resolveCallingPackageNameEnforcingSecurity( 919 @NonNull String packageName) { 920 String[] packages = mContext.getPackageManager().getPackagesForUid( 921 Binder.getCallingUid()); 922 final int packageCount = packages.length; 923 for (int i = 0; i < packageCount; i++) { 924 if (packageName.equals(packages[i])) { 925 return packageName; 926 } 927 } 928 throw new IllegalArgumentException("packageName has to belong to the caller"); 929 } 930 931 private int getCurrentUserId () { 932 final long identity = Binder.clearCallingIdentity(); 933 try { 934 return ActivityManager.getCurrentUser(); 935 } finally { 936 Binder.restoreCallingIdentity(identity); 937 } 938 } 939 } 940} 941