PrintManagerService.java revision 7bfbbcb04bf4ba8f3069b2df136f708c9849bacf
1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server.print; 18 19import android.Manifest; 20import android.app.Notification; 21import android.app.NotificationManager; 22import android.app.PendingIntent; 23import android.content.BroadcastReceiver; 24import android.content.ComponentName; 25import android.content.Context; 26import android.content.Intent; 27import android.content.IntentFilter; 28import android.content.pm.PackageManager; 29import android.content.pm.ResolveInfo; 30import android.content.pm.ServiceInfo; 31import android.database.ContentObserver; 32import android.net.Uri; 33import android.os.Binder; 34import android.os.Bundle; 35import android.os.Process; 36import android.os.RemoteException; 37import android.os.UserHandle; 38import android.print.IPrintDocumentAdapter; 39import android.print.IPrintJobStateChangeListener; 40import android.print.IPrintManager; 41import android.print.IPrinterDiscoveryObserver; 42import android.print.PrintAttributes; 43import android.print.PrintJobId; 44import android.print.PrintJobInfo; 45import android.print.PrinterId; 46import android.printservice.PrintServiceInfo; 47import android.provider.Settings; 48import android.text.TextUtils; 49import android.util.SparseArray; 50 51import com.android.internal.R; 52import com.android.internal.content.PackageMonitor; 53import com.android.internal.os.BackgroundThread; 54 55import java.io.FileDescriptor; 56import java.io.PrintWriter; 57import java.util.Iterator; 58import java.util.List; 59import java.util.Set; 60 61public 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 pw.println("PRINT MANAGER STATE (dumpsys print)"); 365 final int userStateCount = mUserStates.size(); 366 for (int i = 0; i < userStateCount; i++) { 367 UserState userState = mUserStates.get(i); 368 userState.dump(fd, pw, ""); 369 pw.println(); 370 } 371 } 372 } 373 374 private void registerContentObservers() { 375 final Uri enabledPrintServicesUri = Settings.Secure.getUriFor( 376 Settings.Secure.ENABLED_PRINT_SERVICES); 377 378 ContentObserver observer = new ContentObserver(BackgroundThread.getHandler()) { 379 @Override 380 public void onChange(boolean selfChange, Uri uri) { 381 if (enabledPrintServicesUri.equals(uri)) { 382 synchronized (mLock) { 383 UserState userState = getCurrentUserStateLocked(); 384 userState.updateIfNeededLocked(); 385 } 386 } 387 } 388 }; 389 390 mContext.getContentResolver().registerContentObserver(enabledPrintServicesUri, 391 false, observer, UserHandle.USER_ALL); 392 } 393 394 private void registerBoradcastReceivers() { 395 PackageMonitor monitor = new PackageMonitor() { 396 @Override 397 public boolean onPackageChanged(String packageName, int uid, String[] components) { 398 synchronized (mLock) { 399 UserState userState = getOrCreateUserStateLocked(getChangingUserId()); 400 Iterator<ComponentName> iterator = userState.getEnabledServices().iterator(); 401 while (iterator.hasNext()) { 402 ComponentName componentName = iterator.next(); 403 if (packageName.equals(componentName.getPackageName())) { 404 userState.updateIfNeededLocked(); 405 return true; 406 } 407 } 408 } 409 return false; 410 } 411 412 @Override 413 public void onPackageRemoved(String packageName, int uid) { 414 synchronized (mLock) { 415 UserState userState = getOrCreateUserStateLocked(getChangingUserId()); 416 Iterator<ComponentName> iterator = userState.getEnabledServices().iterator(); 417 while (iterator.hasNext()) { 418 ComponentName componentName = iterator.next(); 419 if (packageName.equals(componentName.getPackageName())) { 420 iterator.remove(); 421 persistComponentNamesToSettingLocked( 422 Settings.Secure.ENABLED_PRINT_SERVICES, 423 userState.getEnabledServices(), getChangingUserId()); 424 userState.updateIfNeededLocked(); 425 return; 426 } 427 } 428 } 429 } 430 431 @Override 432 public boolean onHandleForceStop(Intent intent, String[] stoppedPackages, 433 int uid, boolean doit) { 434 synchronized (mLock) { 435 UserState userState = getOrCreateUserStateLocked(getChangingUserId()); 436 boolean stoppedSomePackages = false; 437 Iterator<ComponentName> iterator = userState.getEnabledServices().iterator(); 438 while (iterator.hasNext()) { 439 ComponentName componentName = iterator.next(); 440 String componentPackage = componentName.getPackageName(); 441 for (String stoppedPackage : stoppedPackages) { 442 if (componentPackage.equals(stoppedPackage)) { 443 if (!doit) { 444 return true; 445 } 446 stoppedSomePackages = true; 447 break; 448 } 449 } 450 } 451 if (stoppedSomePackages) { 452 userState.updateIfNeededLocked(); 453 } 454 return false; 455 } 456 } 457 458 @Override 459 public void onPackageAdded(String packageName, int uid) { 460 Intent intent = new Intent(android.printservice.PrintService.SERVICE_INTERFACE); 461 intent.setPackage(packageName); 462 463 List<ResolveInfo> installedServices = mContext.getPackageManager() 464 .queryIntentServicesAsUser(intent, PackageManager.GET_SERVICES, 465 getChangingUserId()); 466 467 if (installedServices == null) { 468 return; 469 } 470 471 final int installedServiceCount = installedServices.size(); 472 for (int i = 0; i < installedServiceCount; i++) { 473 ServiceInfo serviceInfo = installedServices.get(i).serviceInfo; 474 ComponentName component = new ComponentName(serviceInfo.packageName, 475 serviceInfo.name); 476 String label = serviceInfo.loadLabel(mContext.getPackageManager()).toString(); 477 showEnableInstalledPrintServiceNotification(component, label); 478 } 479 } 480 481 private void persistComponentNamesToSettingLocked(String settingName, 482 Set<ComponentName> componentNames, int userId) { 483 StringBuilder builder = new StringBuilder(); 484 for (ComponentName componentName : componentNames) { 485 if (builder.length() > 0) { 486 builder.append(COMPONENT_NAME_SEPARATOR); 487 } 488 builder.append(componentName.flattenToShortString()); 489 } 490 Settings.Secure.putStringForUser(mContext.getContentResolver(), 491 settingName, builder.toString(), userId); 492 } 493 }; 494 495 // package changes 496 monitor.register(mContext, BackgroundThread.getHandler().getLooper(), 497 UserHandle.ALL, true); 498 499 // user changes 500 IntentFilter intentFilter = new IntentFilter(); 501 intentFilter.addAction(Intent.ACTION_USER_SWITCHED); 502 intentFilter.addAction(Intent.ACTION_USER_REMOVED); 503 504 mContext.registerReceiverAsUser(new BroadcastReceiver() { 505 @Override 506 public void onReceive(Context context, Intent intent) { 507 String action = intent.getAction(); 508 if (Intent.ACTION_USER_SWITCHED.equals(action)) { 509 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); 510 } else if (Intent.ACTION_USER_REMOVED.equals(action)) { 511 removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); 512 } 513 } 514 }, UserHandle.ALL, intentFilter, null, BackgroundThread.getHandler()); 515 } 516 517 private UserState getCurrentUserStateLocked() { 518 return getOrCreateUserStateLocked(mCurrentUserId); 519 } 520 521 private UserState getOrCreateUserStateLocked(int userId) { 522 UserState userState = mUserStates.get(userId); 523 if (userState == null) { 524 userState = new UserState(mContext, userId, mLock); 525 mUserStates.put(userId, userState); 526 } 527 return userState; 528 } 529 530 private void switchUser(int newUserId) { 531 UserState userState; 532 synchronized (mLock) { 533 if (newUserId == mCurrentUserId) { 534 return; 535 } 536 mCurrentUserId = newUserId; 537 userState = mUserStates.get(mCurrentUserId); 538 if (userState == null) { 539 userState = getCurrentUserStateLocked(); 540 userState.updateIfNeededLocked(); 541 } else { 542 userState.updateIfNeededLocked(); 543 } 544 } 545 // This is the first time we switch to this user after boot, so 546 // now is the time to remove obsolete print jobs since they 547 // are from the last boot and no application would query them. 548 userState.removeObsoletePrintJobs(); 549 } 550 551 private void removeUser(int removedUserId) { 552 synchronized (mLock) { 553 UserState userState = mUserStates.get(removedUserId); 554 if (userState != null) { 555 userState.destroyLocked(); 556 mUserStates.remove(removedUserId); 557 } 558 } 559 } 560 561 private int resolveCallingAppEnforcingPermissions(int appId) { 562 final int callingUid = Binder.getCallingUid(); 563 if (callingUid == 0 || callingUid == Process.SYSTEM_UID 564 || callingUid == Process.SHELL_UID) { 565 return appId; 566 } 567 final int callingAppId = UserHandle.getAppId(callingUid); 568 if (appId == callingAppId) { 569 return appId; 570 } 571 if (mContext.checkCallingPermission( 572 "com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS") 573 != PackageManager.PERMISSION_GRANTED) { 574 throw new SecurityException("Call from app " + callingAppId + " as app " 575 + appId + " without com.android.printspooler.permission" 576 + ".ACCESS_ALL_PRINT_JOBS"); 577 } 578 return appId; 579 } 580 581 private int resolveCallingUserEnforcingPermissions(int userId) { 582 final int callingUid = Binder.getCallingUid(); 583 if (callingUid == 0 || callingUid == Process.SYSTEM_UID 584 || callingUid == Process.SHELL_UID) { 585 return userId; 586 } 587 final int callingUserId = UserHandle.getUserId(callingUid); 588 if (callingUserId == userId) { 589 return userId; 590 } 591 if (mContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL) 592 != PackageManager.PERMISSION_GRANTED 593 || mContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS) 594 != PackageManager.PERMISSION_GRANTED) { 595 if (userId == UserHandle.USER_CURRENT_OR_SELF) { 596 return callingUserId; 597 } 598 throw new SecurityException("Call from user " + callingUserId + " as user " 599 + userId + " without permission INTERACT_ACROSS_USERS or " 600 + "INTERACT_ACROSS_USERS_FULL not allowed."); 601 } 602 if (userId == UserHandle.USER_CURRENT || userId == UserHandle.USER_CURRENT_OR_SELF) { 603 return mCurrentUserId; 604 } 605 throw new IllegalArgumentException("Calling user can be changed to only " 606 + "UserHandle.USER_CURRENT or UserHandle.USER_CURRENT_OR_SELF."); 607 } 608 609 private String resolveCallingPackageNameEnforcingSecurity(String packageName) { 610 if (TextUtils.isEmpty(packageName)) { 611 return null; 612 } 613 String[] packages = mContext.getPackageManager().getPackagesForUid( 614 Binder.getCallingUid()); 615 final int packageCount = packages.length; 616 for (int i = 0; i < packageCount; i++) { 617 if (packageName.equals(packages[i])) { 618 return packageName; 619 } 620 } 621 return null; 622 } 623 624 private void showEnableInstalledPrintServiceNotification(ComponentName component, 625 String label) { 626 Intent intent = new Intent(Settings.ACTION_PRINT_SETTINGS); 627 intent.putExtra(EXTRA_PRINT_SERVICE_COMPONENT_NAME, component.flattenToString()); 628 629 PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, 630 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT, null); 631 632 Notification.Builder builder = new Notification.Builder(mContext) 633 .setSmallIcon(R.drawable.ic_print) 634 .setContentTitle(mContext.getString(R.string.print_service_installed_title, label)) 635 .setContentText(mContext.getString(R.string.print_service_installed_message)) 636 .setContentIntent(pendingIntent) 637 .setWhen(System.currentTimeMillis()) 638 .setAutoCancel(true) 639 .setShowWhen(true); 640 641 NotificationManager notificationManager = (NotificationManager) mContext 642 .getSystemService(Context.NOTIFICATION_SERVICE); 643 644 String notificationTag = getClass().getName() + ":" + component.flattenToString(); 645 notificationManager.notify(notificationTag, 0, builder.build()); 646 } 647} 648