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 android.Manifest; 20 import android.app.Notification; 21 import android.app.NotificationManager; 22 import android.app.PendingIntent; 23 import android.content.BroadcastReceiver; 24 import android.content.ComponentName; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.IntentFilter; 28 import android.content.pm.PackageManager; 29 import android.content.pm.ResolveInfo; 30 import android.content.pm.ServiceInfo; 31 import android.database.ContentObserver; 32 import android.net.Uri; 33 import android.os.Binder; 34 import android.os.Bundle; 35 import android.os.Process; 36 import android.os.RemoteException; 37 import android.os.UserHandle; 38 import android.print.IPrintDocumentAdapter; 39 import android.print.IPrintJobStateChangeListener; 40 import android.print.IPrintManager; 41 import android.print.IPrinterDiscoveryObserver; 42 import android.print.PrintAttributes; 43 import android.print.PrintJobId; 44 import android.print.PrintJobInfo; 45 import android.print.PrinterId; 46 import android.printservice.PrintServiceInfo; 47 import android.provider.Settings; 48 import android.text.TextUtils; 49 import android.util.SparseArray; 50 51 import com.android.internal.R; 52 import com.android.internal.content.PackageMonitor; 53 import com.android.internal.os.BackgroundThread; 54 55 import java.io.FileDescriptor; 56 import java.io.PrintWriter; 57 import java.util.Iterator; 58 import java.util.List; 59 import java.util.Set; 60 61 public final class PrintManagerService extends IPrintManager.Stub { 62 63 private static final char COMPONENT_NAME_SEPARATOR = ':'; 64 65 private static final String EXTRA_PRINT_SERVICE_COMPONENT_NAME = 66 "EXTRA_PRINT_SERVICE_COMPONENT_NAME"; 67 68 private final Object mLock = new Object(); 69 70 private final Context mContext; 71 72 private final SparseArray<UserState> mUserStates = new SparseArray<UserState>(); 73 74 private int mCurrentUserId = UserHandle.USER_OWNER; 75 76 public PrintManagerService(Context context) { 77 mContext = context; 78 registerContentObservers(); 79 registerBoradcastReceivers(); 80 } 81 82 public void systemRuning() { 83 BackgroundThread.getHandler().post(new Runnable() { 84 @Override 85 public void run() { 86 final UserState userState; 87 synchronized (mLock) { 88 userState = getCurrentUserStateLocked(); 89 userState.updateIfNeededLocked(); 90 } 91 // This is the first time we switch to this user after boot, so 92 // now is the time to remove obsolete print jobs since they 93 // are from the last boot and no application would query them. 94 userState.removeObsoletePrintJobs(); 95 } 96 }); 97 } 98 99 @Override 100 public Bundle print(String printJobName, IPrintDocumentAdapter adapter, 101 PrintAttributes attributes, String packageName, int appId, int userId) { 102 final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId); 103 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 104 String resolvedPackageName = resolveCallingPackageNameEnforcingSecurity(packageName); 105 final UserState userState; 106 synchronized (mLock) { 107 userState = getOrCreateUserStateLocked(resolvedUserId); 108 } 109 final long identity = Binder.clearCallingIdentity(); 110 try { 111 return userState.print(printJobName, adapter, attributes, 112 resolvedPackageName, resolvedAppId); 113 } finally { 114 Binder.restoreCallingIdentity(identity); 115 } 116 } 117 118 @Override 119 public List<PrintJobInfo> getPrintJobInfos(int appId, int userId) { 120 final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId); 121 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 122 final UserState userState; 123 synchronized (mLock) { 124 userState = getOrCreateUserStateLocked(resolvedUserId); 125 } 126 final long identity = Binder.clearCallingIdentity(); 127 try { 128 return userState.getPrintJobInfos(resolvedAppId); 129 } finally { 130 Binder.restoreCallingIdentity(identity); 131 } 132 } 133 134 @Override 135 public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId, int userId) { 136 final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId); 137 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 138 final UserState userState; 139 synchronized (mLock) { 140 userState = getOrCreateUserStateLocked(resolvedUserId); 141 } 142 final long identity = Binder.clearCallingIdentity(); 143 try { 144 return userState.getPrintJobInfo(printJobId, resolvedAppId); 145 } finally { 146 Binder.restoreCallingIdentity(identity); 147 } 148 } 149 150 @Override 151 public void cancelPrintJob(PrintJobId printJobId, int appId, int userId) { 152 final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId); 153 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 154 final UserState userState; 155 synchronized (mLock) { 156 userState = getOrCreateUserStateLocked(resolvedUserId); 157 } 158 final long identity = Binder.clearCallingIdentity(); 159 try { 160 userState.cancelPrintJob(printJobId, resolvedAppId); 161 } finally { 162 Binder.restoreCallingIdentity(identity); 163 } 164 } 165 166 @Override 167 public void restartPrintJob(PrintJobId printJobId, int appId, int userId) { 168 final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId); 169 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 170 final UserState userState; 171 synchronized (mLock) { 172 userState = getOrCreateUserStateLocked(resolvedUserId); 173 } 174 final long identity = Binder.clearCallingIdentity(); 175 try { 176 userState.restartPrintJob(printJobId, resolvedAppId); 177 } finally { 178 Binder.restoreCallingIdentity(identity); 179 } 180 } 181 182 @Override 183 public List<PrintServiceInfo> getEnabledPrintServices(int userId) { 184 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 185 final UserState userState; 186 synchronized (mLock) { 187 userState = getOrCreateUserStateLocked(resolvedUserId); 188 } 189 final long identity = Binder.clearCallingIdentity(); 190 try { 191 return userState.getEnabledPrintServices(); 192 } finally { 193 Binder.restoreCallingIdentity(identity); 194 } 195 } 196 197 @Override 198 public List<PrintServiceInfo> getInstalledPrintServices(int userId) { 199 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 200 final UserState userState; 201 synchronized (mLock) { 202 userState = getOrCreateUserStateLocked(resolvedUserId); 203 } 204 final long identity = Binder.clearCallingIdentity(); 205 try { 206 return userState.getInstalledPrintServices(); 207 } finally { 208 Binder.restoreCallingIdentity(identity); 209 } 210 } 211 212 @Override 213 public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer, 214 int userId) { 215 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 216 final UserState userState; 217 synchronized (mLock) { 218 userState = getOrCreateUserStateLocked(resolvedUserId); 219 } 220 final long identity = Binder.clearCallingIdentity(); 221 try { 222 userState.createPrinterDiscoverySession(observer); 223 } finally { 224 Binder.restoreCallingIdentity(identity); 225 } 226 } 227 228 @Override 229 public void destroyPrinterDiscoverySession(IPrinterDiscoveryObserver observer, 230 int userId) { 231 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 232 final UserState userState; 233 synchronized (mLock) { 234 userState = getOrCreateUserStateLocked(resolvedUserId); 235 } 236 final long identity = Binder.clearCallingIdentity(); 237 try { 238 userState.destroyPrinterDiscoverySession(observer); 239 } finally { 240 Binder.restoreCallingIdentity(identity); 241 } 242 } 243 244 @Override 245 public void startPrinterDiscovery(IPrinterDiscoveryObserver observer, 246 List<PrinterId> priorityList, int userId) { 247 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 248 final UserState userState; 249 synchronized (mLock) { 250 userState = getOrCreateUserStateLocked(resolvedUserId); 251 } 252 final long identity = Binder.clearCallingIdentity(); 253 try { 254 userState.startPrinterDiscovery(observer, priorityList); 255 } finally { 256 Binder.restoreCallingIdentity(identity); 257 } 258 } 259 260 @Override 261 public void stopPrinterDiscovery(IPrinterDiscoveryObserver observer, int userId) { 262 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 263 final UserState userState; 264 synchronized (mLock) { 265 userState = getOrCreateUserStateLocked(resolvedUserId); 266 } 267 final long identity = Binder.clearCallingIdentity(); 268 try { 269 userState.stopPrinterDiscovery(observer); 270 } finally { 271 Binder.restoreCallingIdentity(identity); 272 } 273 } 274 275 @Override 276 public void validatePrinters(List<PrinterId> printerIds, int userId) { 277 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 278 final UserState userState; 279 synchronized (mLock) { 280 userState = getOrCreateUserStateLocked(resolvedUserId); 281 } 282 final long identity = Binder.clearCallingIdentity(); 283 try { 284 userState.validatePrinters(printerIds); 285 } finally { 286 Binder.restoreCallingIdentity(identity); 287 } 288 } 289 290 @Override 291 public void startPrinterStateTracking(PrinterId printerId, int userId) { 292 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 293 final UserState userState; 294 synchronized (mLock) { 295 userState = getOrCreateUserStateLocked(resolvedUserId); 296 } 297 final long identity = Binder.clearCallingIdentity(); 298 try { 299 userState.startPrinterStateTracking(printerId); 300 } finally { 301 Binder.restoreCallingIdentity(identity); 302 } 303 } 304 305 @Override 306 public void stopPrinterStateTracking(PrinterId printerId, int userId) { 307 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 308 final UserState userState; 309 synchronized (mLock) { 310 userState = getOrCreateUserStateLocked(resolvedUserId); 311 } 312 final long identity = Binder.clearCallingIdentity(); 313 try { 314 userState.stopPrinterStateTracking(printerId); 315 } finally { 316 Binder.restoreCallingIdentity(identity); 317 } 318 } 319 320 @Override 321 public void addPrintJobStateChangeListener(IPrintJobStateChangeListener listener, 322 int appId, int userId) throws RemoteException { 323 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 324 final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId); 325 final UserState userState; 326 synchronized (mLock) { 327 userState = getOrCreateUserStateLocked(resolvedUserId); 328 } 329 final long identity = Binder.clearCallingIdentity(); 330 try { 331 userState.addPrintJobStateChangeListener(listener, resolvedAppId); 332 } finally { 333 Binder.restoreCallingIdentity(identity); 334 } 335 } 336 337 @Override 338 public void removePrintJobStateChangeListener(IPrintJobStateChangeListener listener, 339 int userId) { 340 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 341 final UserState userState; 342 synchronized (mLock) { 343 userState = getOrCreateUserStateLocked(resolvedUserId); 344 } 345 final long identity = Binder.clearCallingIdentity(); 346 try { 347 userState.removePrintJobStateChangeListener(listener); 348 } finally { 349 Binder.restoreCallingIdentity(identity); 350 } 351 } 352 353 @Override 354 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 355 if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) 356 != PackageManager.PERMISSION_GRANTED) { 357 pw.println("Permission Denial: can't dump PrintManager from from pid=" 358 + Binder.getCallingPid() 359 + ", uid=" + Binder.getCallingUid()); 360 return; 361 } 362 363 synchronized (mLock) { 364 final long identity = Binder.clearCallingIdentity(); 365 try { 366 pw.println("PRINT MANAGER STATE (dumpsys print)"); 367 final int userStateCount = mUserStates.size(); 368 for (int i = 0; i < userStateCount; i++) { 369 UserState userState = mUserStates.valueAt(i); 370 userState.dump(fd, pw, ""); 371 pw.println(); 372 } 373 } finally { 374 Binder.restoreCallingIdentity(identity); 375 } 376 } 377 } 378 379 private void registerContentObservers() { 380 final Uri enabledPrintServicesUri = Settings.Secure.getUriFor( 381 Settings.Secure.ENABLED_PRINT_SERVICES); 382 383 ContentObserver observer = new ContentObserver(BackgroundThread.getHandler()) { 384 @Override 385 public void onChange(boolean selfChange, Uri uri) { 386 if (enabledPrintServicesUri.equals(uri)) { 387 synchronized (mLock) { 388 UserState userState = getCurrentUserStateLocked(); 389 userState.updateIfNeededLocked(); 390 } 391 } 392 } 393 }; 394 395 mContext.getContentResolver().registerContentObserver(enabledPrintServicesUri, 396 false, observer, UserHandle.USER_ALL); 397 } 398 399 private void registerBoradcastReceivers() { 400 PackageMonitor monitor = new PackageMonitor() { 401 @Override 402 public boolean onPackageChanged(String packageName, int uid, String[] components) { 403 synchronized (mLock) { 404 UserState userState = getOrCreateUserStateLocked(getChangingUserId()); 405 Iterator<ComponentName> iterator = userState.getEnabledServices().iterator(); 406 while (iterator.hasNext()) { 407 ComponentName componentName = iterator.next(); 408 if (packageName.equals(componentName.getPackageName())) { 409 userState.updateIfNeededLocked(); 410 return true; 411 } 412 } 413 } 414 return false; 415 } 416 417 @Override 418 public void onPackageRemoved(String packageName, int uid) { 419 synchronized (mLock) { 420 UserState userState = getOrCreateUserStateLocked(getChangingUserId()); 421 Iterator<ComponentName> iterator = userState.getEnabledServices().iterator(); 422 while (iterator.hasNext()) { 423 ComponentName componentName = iterator.next(); 424 if (packageName.equals(componentName.getPackageName())) { 425 iterator.remove(); 426 persistComponentNamesToSettingLocked( 427 Settings.Secure.ENABLED_PRINT_SERVICES, 428 userState.getEnabledServices(), getChangingUserId()); 429 userState.updateIfNeededLocked(); 430 return; 431 } 432 } 433 } 434 } 435 436 @Override 437 public boolean onHandleForceStop(Intent intent, String[] stoppedPackages, 438 int uid, boolean doit) { 439 synchronized (mLock) { 440 UserState userState = getOrCreateUserStateLocked(getChangingUserId()); 441 boolean stoppedSomePackages = false; 442 Iterator<ComponentName> iterator = userState.getEnabledServices().iterator(); 443 while (iterator.hasNext()) { 444 ComponentName componentName = iterator.next(); 445 String componentPackage = componentName.getPackageName(); 446 for (String stoppedPackage : stoppedPackages) { 447 if (componentPackage.equals(stoppedPackage)) { 448 if (!doit) { 449 return true; 450 } 451 stoppedSomePackages = true; 452 break; 453 } 454 } 455 } 456 if (stoppedSomePackages) { 457 userState.updateIfNeededLocked(); 458 } 459 return false; 460 } 461 } 462 463 @Override 464 public void onPackageAdded(String packageName, int uid) { 465 Intent intent = new Intent(android.printservice.PrintService.SERVICE_INTERFACE); 466 intent.setPackage(packageName); 467 468 List<ResolveInfo> installedServices = mContext.getPackageManager() 469 .queryIntentServicesAsUser(intent, PackageManager.GET_SERVICES, 470 getChangingUserId()); 471 472 if (installedServices == null) { 473 return; 474 } 475 476 final int installedServiceCount = installedServices.size(); 477 for (int i = 0; i < installedServiceCount; i++) { 478 ServiceInfo serviceInfo = installedServices.get(i).serviceInfo; 479 ComponentName component = new ComponentName(serviceInfo.packageName, 480 serviceInfo.name); 481 String label = serviceInfo.loadLabel(mContext.getPackageManager()).toString(); 482 showEnableInstalledPrintServiceNotification(component, label, 483 getChangingUserId()); 484 } 485 } 486 487 private void persistComponentNamesToSettingLocked(String settingName, 488 Set<ComponentName> componentNames, int userId) { 489 StringBuilder builder = new StringBuilder(); 490 for (ComponentName componentName : componentNames) { 491 if (builder.length() > 0) { 492 builder.append(COMPONENT_NAME_SEPARATOR); 493 } 494 builder.append(componentName.flattenToShortString()); 495 } 496 Settings.Secure.putStringForUser(mContext.getContentResolver(), 497 settingName, builder.toString(), userId); 498 } 499 }; 500 501 // package changes 502 monitor.register(mContext, BackgroundThread.getHandler().getLooper(), 503 UserHandle.ALL, true); 504 505 // user changes 506 IntentFilter intentFilter = new IntentFilter(); 507 intentFilter.addAction(Intent.ACTION_USER_SWITCHED); 508 intentFilter.addAction(Intent.ACTION_USER_REMOVED); 509 510 mContext.registerReceiverAsUser(new BroadcastReceiver() { 511 @Override 512 public void onReceive(Context context, Intent intent) { 513 String action = intent.getAction(); 514 if (Intent.ACTION_USER_SWITCHED.equals(action)) { 515 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); 516 } else if (Intent.ACTION_USER_REMOVED.equals(action)) { 517 removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); 518 } 519 } 520 }, UserHandle.ALL, intentFilter, null, BackgroundThread.getHandler()); 521 } 522 523 private UserState getCurrentUserStateLocked() { 524 return getOrCreateUserStateLocked(mCurrentUserId); 525 } 526 527 private UserState getOrCreateUserStateLocked(int userId) { 528 UserState userState = mUserStates.get(userId); 529 if (userState == null) { 530 userState = new UserState(mContext, userId, mLock); 531 mUserStates.put(userId, userState); 532 } 533 return userState; 534 } 535 536 private void switchUser(int newUserId) { 537 UserState userState; 538 synchronized (mLock) { 539 if (newUserId == mCurrentUserId) { 540 return; 541 } 542 mCurrentUserId = newUserId; 543 userState = mUserStates.get(mCurrentUserId); 544 if (userState == null) { 545 userState = getCurrentUserStateLocked(); 546 userState.updateIfNeededLocked(); 547 } else { 548 userState.updateIfNeededLocked(); 549 } 550 } 551 // This is the first time we switch to this user after boot, so 552 // now is the time to remove obsolete print jobs since they 553 // are from the last boot and no application would query them. 554 userState.removeObsoletePrintJobs(); 555 } 556 557 private void removeUser(int removedUserId) { 558 synchronized (mLock) { 559 UserState userState = mUserStates.get(removedUserId); 560 if (userState != null) { 561 userState.destroyLocked(); 562 mUserStates.remove(removedUserId); 563 } 564 } 565 } 566 567 private int resolveCallingAppEnforcingPermissions(int appId) { 568 final int callingUid = Binder.getCallingUid(); 569 if (callingUid == 0 || callingUid == Process.SYSTEM_UID 570 || callingUid == Process.SHELL_UID) { 571 return appId; 572 } 573 final int callingAppId = UserHandle.getAppId(callingUid); 574 if (appId == callingAppId) { 575 return appId; 576 } 577 if (mContext.checkCallingPermission( 578 "com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS") 579 != PackageManager.PERMISSION_GRANTED) { 580 throw new SecurityException("Call from app " + callingAppId + " as app " 581 + appId + " without com.android.printspooler.permission" 582 + ".ACCESS_ALL_PRINT_JOBS"); 583 } 584 return appId; 585 } 586 587 private int resolveCallingUserEnforcingPermissions(int userId) { 588 final int callingUid = Binder.getCallingUid(); 589 if (callingUid == 0 || callingUid == Process.SYSTEM_UID 590 || callingUid == Process.SHELL_UID) { 591 return userId; 592 } 593 final int callingUserId = UserHandle.getUserId(callingUid); 594 if (callingUserId == userId) { 595 return userId; 596 } 597 if (mContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL) 598 != PackageManager.PERMISSION_GRANTED 599 || mContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS) 600 != PackageManager.PERMISSION_GRANTED) { 601 if (userId == UserHandle.USER_CURRENT_OR_SELF) { 602 return callingUserId; 603 } 604 throw new SecurityException("Call from user " + callingUserId + " as user " 605 + userId + " without permission INTERACT_ACROSS_USERS or " 606 + "INTERACT_ACROSS_USERS_FULL not allowed."); 607 } 608 if (userId == UserHandle.USER_CURRENT || userId == UserHandle.USER_CURRENT_OR_SELF) { 609 return mCurrentUserId; 610 } 611 throw new IllegalArgumentException("Calling user can be changed to only " 612 + "UserHandle.USER_CURRENT or UserHandle.USER_CURRENT_OR_SELF."); 613 } 614 615 private String resolveCallingPackageNameEnforcingSecurity(String packageName) { 616 if (TextUtils.isEmpty(packageName)) { 617 return null; 618 } 619 String[] packages = mContext.getPackageManager().getPackagesForUid( 620 Binder.getCallingUid()); 621 final int packageCount = packages.length; 622 for (int i = 0; i < packageCount; i++) { 623 if (packageName.equals(packages[i])) { 624 return packageName; 625 } 626 } 627 return null; 628 } 629 630 private void showEnableInstalledPrintServiceNotification(ComponentName component, 631 String label, int userId) { 632 UserHandle userHandle = new UserHandle(userId); 633 634 Intent intent = new Intent(Settings.ACTION_PRINT_SETTINGS); 635 intent.putExtra(EXTRA_PRINT_SERVICE_COMPONENT_NAME, component.flattenToString()); 636 637 PendingIntent pendingIntent = PendingIntent.getActivityAsUser(mContext, 0, intent, 638 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT, null, userHandle); 639 640 Notification.Builder builder = new Notification.Builder(mContext) 641 .setSmallIcon(R.drawable.ic_print) 642 .setContentTitle(mContext.getString(R.string.print_service_installed_title, label)) 643 .setContentText(mContext.getString(R.string.print_service_installed_message)) 644 .setContentIntent(pendingIntent) 645 .setWhen(System.currentTimeMillis()) 646 .setAutoCancel(true) 647 .setShowWhen(true); 648 649 NotificationManager notificationManager = (NotificationManager) mContext 650 .getSystemService(Context.NOTIFICATION_SERVICE); 651 652 String notificationTag = getClass().getName() + ":" + component.flattenToString(); 653 notificationManager.notifyAsUser(notificationTag, 0, builder.build(), 654 userHandle); 655 } 656 } 657