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