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