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