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