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