PrintManagerService.java revision 44720af55a8fdf991929983dad5d53c02851dd1e
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.content.BroadcastReceiver; 21import android.content.ComponentName; 22import android.content.Context; 23import android.content.Intent; 24import android.content.IntentFilter; 25import android.content.pm.PackageManager; 26import android.database.ContentObserver; 27import android.net.Uri; 28import android.os.Binder; 29import android.os.Process; 30import android.os.UserHandle; 31import android.print.IPrintClient; 32import android.print.IPrintDocumentAdapter; 33import android.print.IPrintManager; 34import android.print.IPrinterDiscoveryObserver; 35import android.print.PrintAttributes; 36import android.print.PrintJobInfo; 37import android.print.PrinterId; 38import android.provider.Settings; 39import android.util.SparseArray; 40 41import com.android.internal.content.PackageMonitor; 42import com.android.internal.os.BackgroundThread; 43 44import java.util.Iterator; 45import java.util.List; 46import java.util.Set; 47 48public final class PrintManagerService extends IPrintManager.Stub { 49 50 private static final char COMPONENT_NAME_SEPARATOR = ':'; 51 52 private final Object mLock = new Object(); 53 54 private final Context mContext; 55 56 private final SparseArray<UserState> mUserStates = new SparseArray<UserState>(); 57 58 private int mCurrentUserId = UserHandle.USER_OWNER; 59 60 public PrintManagerService(Context context) { 61 mContext = context; 62 registerContentObservers(); 63 registerBoradcastReceivers(); 64 } 65 66 public void systemRuning() { 67 BackgroundThread.getHandler().post(new Runnable() { 68 @Override 69 public void run() { 70 synchronized (mLock) { 71 UserState userState = getCurrentUserStateLocked(); 72 userState.updateIfNeededLocked(); 73 userState.getSpoolerLocked().start(); 74 } 75 } 76 }); 77 } 78 79 @Override 80 public PrintJobInfo print(String printJobName, IPrintClient client, 81 IPrintDocumentAdapter documentAdapter, PrintAttributes attributes, int appId, 82 int userId) { 83 final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId); 84 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 85 final UserState userState; 86 final RemotePrintSpooler spooler; 87 synchronized (mLock) { 88 userState = getOrCreateUserStateLocked(resolvedUserId); 89 spooler = userState.getSpoolerLocked(); 90 } 91 final long identity = Binder.clearCallingIdentity(); 92 try { 93 return spooler.createPrintJob(printJobName, client, documentAdapter, 94 attributes, resolvedAppId); 95 } finally { 96 Binder.restoreCallingIdentity(identity); 97 } 98 } 99 100 @Override 101 public List<PrintJobInfo> getPrintJobInfos(int appId, int userId) { 102 final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId); 103 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 104 final UserState userState; 105 final RemotePrintSpooler spooler; 106 synchronized (mLock) { 107 userState = getOrCreateUserStateLocked(resolvedUserId); 108 spooler = userState.getSpoolerLocked(); 109 } 110 final long identity = Binder.clearCallingIdentity(); 111 try { 112 return spooler.getPrintJobInfos(null, PrintJobInfo.STATE_ANY, 113 resolvedAppId); 114 } finally { 115 Binder.restoreCallingIdentity(identity); 116 } 117 } 118 119 @Override 120 public PrintJobInfo getPrintJobInfo(int printJobId, int appId, int userId) { 121 final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId); 122 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 123 final UserState userState; 124 final RemotePrintSpooler spooler; 125 synchronized (mLock) { 126 userState = getOrCreateUserStateLocked(resolvedUserId); 127 spooler = userState.getSpoolerLocked(); 128 } 129 final long identity = Binder.clearCallingIdentity(); 130 try { 131 return spooler.getPrintJobInfo(printJobId, resolvedAppId); 132 } finally { 133 Binder.restoreCallingIdentity(identity); 134 } 135 } 136 137 @Override 138 public void cancelPrintJob(int printJobId, int appId, int userId) { 139 final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId); 140 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 141 final UserState userState; 142 final RemotePrintSpooler spooler; 143 synchronized (mLock) { 144 userState = getOrCreateUserStateLocked(resolvedUserId); 145 spooler = userState.getSpoolerLocked(); 146 } 147 final long identity = Binder.clearCallingIdentity(); 148 try { 149 PrintJobInfo printJobInfo = spooler.getPrintJobInfo(printJobId, resolvedAppId); 150 if (printJobInfo == null) { 151 return; 152 } 153 if (printJobInfo.getState() != PrintJobInfo.STATE_FAILED) { 154 ComponentName printServiceName = printJobInfo.getPrinterId().getServiceName(); 155 RemotePrintService printService = null; 156 synchronized (mLock) { 157 printService = userState.getActiveServicesLocked().get(printServiceName); 158 } 159 if (printService == null) { 160 return; 161 } 162 printService.onRequestCancelPrintJob(printJobInfo); 163 } else { 164 // If the print job is failed we do not need cooperation 165 // from the print service. 166 spooler.setPrintJobState(printJobId, PrintJobInfo.STATE_CANCELED, null); 167 } 168 } finally { 169 Binder.restoreCallingIdentity(identity); 170 } 171 } 172 173 @Override 174 public void restartPrintJob(int printJobId, int appId, int userId) { 175 final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId); 176 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 177 final RemotePrintSpooler spooler; 178 synchronized (mLock) { 179 spooler = getOrCreateUserStateLocked(resolvedUserId).getSpoolerLocked(); 180 } 181 final long identity = Binder.clearCallingIdentity(); 182 try { 183 PrintJobInfo printJobInfo = getPrintJobInfo(printJobId, resolvedAppId, resolvedUserId); 184 if (printJobInfo == null || printJobInfo.getState() != PrintJobInfo.STATE_FAILED) { 185 return; 186 } 187 spooler.setPrintJobState(printJobId, PrintJobInfo.STATE_QUEUED, null); 188 } finally { 189 Binder.restoreCallingIdentity(identity); 190 } 191 } 192 193 @Override 194 public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer, 195 int userId) { 196 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 197 final UserState userState; 198 synchronized (mLock) { 199 userState = getOrCreateUserStateLocked(resolvedUserId); 200 } 201 final long identity = Binder.clearCallingIdentity(); 202 try { 203 userState.createPrinterDiscoverySession(observer); 204 } finally { 205 Binder.restoreCallingIdentity(identity); 206 } 207 } 208 209 @Override 210 public void destroyPrinterDiscoverySession(IPrinterDiscoveryObserver observer, 211 int userId) { 212 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 213 final UserState userState; 214 synchronized (mLock) { 215 userState = getOrCreateUserStateLocked(resolvedUserId); 216 } 217 final long identity = Binder.clearCallingIdentity(); 218 try { 219 userState.destroyPrinterDiscoverySession(observer); 220 } finally { 221 Binder.restoreCallingIdentity(identity); 222 } 223 } 224 225 @Override 226 public void startPrinterDiscovery(IPrinterDiscoveryObserver observer, 227 List<PrinterId> priorityList, int userId) { 228 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 229 final UserState userState; 230 synchronized (mLock) { 231 userState = getOrCreateUserStateLocked(resolvedUserId); 232 } 233 final long identity = Binder.clearCallingIdentity(); 234 try { 235 userState.startPrinterDiscovery(observer, priorityList); 236 } finally { 237 Binder.restoreCallingIdentity(identity); 238 } 239 } 240 241 @Override 242 public void stopPrinterDiscovery(IPrinterDiscoveryObserver observer, int userId) { 243 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 244 final UserState userState; 245 synchronized (mLock) { 246 userState = getOrCreateUserStateLocked(resolvedUserId); 247 } 248 final long identity = Binder.clearCallingIdentity(); 249 try { 250 userState.stopPrinterDiscovery(observer); 251 } finally { 252 Binder.restoreCallingIdentity(identity); 253 } 254 } 255 256 @Override 257 public void requestPrinterUpdate(PrinterId printerId, int userId) { 258 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); 259 final UserState userState; 260 synchronized (mLock) { 261 userState = getOrCreateUserStateLocked(resolvedUserId); 262 } 263 final long identity = Binder.clearCallingIdentity(); 264 try { 265 userState.requestPrinterUpdate(printerId); 266 } finally { 267 Binder.restoreCallingIdentity(identity); 268 } 269 } 270 271 private void registerContentObservers() { 272 final Uri enabledPrintServicesUri = Settings.Secure.getUriFor( 273 Settings.Secure.ENABLED_PRINT_SERVICES); 274 275 ContentObserver observer = new ContentObserver(BackgroundThread.getHandler()) { 276 @Override 277 public void onChange(boolean selfChange, Uri uri) { 278 if (enabledPrintServicesUri.equals(uri)) { 279 synchronized (mLock) { 280 UserState userState = getCurrentUserStateLocked(); 281 userState.updateIfNeededLocked(); 282 } 283 } 284 } 285 }; 286 287 mContext.getContentResolver().registerContentObserver(enabledPrintServicesUri, 288 false, observer, UserHandle.USER_ALL); 289 } 290 291 private void registerBoradcastReceivers() { 292 PackageMonitor monitor = new PackageMonitor() { 293 @Override 294 public boolean onPackageChanged(String packageName, int uid, String[] components) { 295 synchronized (mLock) { 296 UserState userState = getOrCreateUserStateLocked(getChangingUserId()); 297 Iterator<ComponentName> iterator = userState.getEnabledServices().iterator(); 298 while (iterator.hasNext()) { 299 ComponentName componentName = iterator.next(); 300 if (packageName.equals(componentName.getPackageName())) { 301 userState.updateIfNeededLocked(); 302 return true; 303 } 304 } 305 } 306 return false; 307 } 308 309 @Override 310 public void onPackageRemoved(String packageName, int uid) { 311 synchronized (mLock) { 312 UserState userState = getOrCreateUserStateLocked(getChangingUserId()); 313 Iterator<ComponentName> iterator = userState.getEnabledServices().iterator(); 314 while (iterator.hasNext()) { 315 ComponentName componentName = iterator.next(); 316 if (packageName.equals(componentName.getPackageName())) { 317 iterator.remove(); 318 persistComponentNamesToSettingLocked( 319 Settings.Secure.ENABLED_PRINT_SERVICES, 320 userState.getEnabledServices(), getChangingUserId()); 321 userState.updateIfNeededLocked(); 322 return; 323 } 324 } 325 } 326 } 327 328 @Override 329 public boolean onHandleForceStop(Intent intent, String[] stoppedPackages, 330 int uid, boolean doit) { 331 synchronized (mLock) { 332 UserState userState = getOrCreateUserStateLocked(getChangingUserId()); 333 boolean stoppedSomePackages = false; 334 Iterator<ComponentName> iterator = userState.getEnabledServices().iterator(); 335 while (iterator.hasNext()) { 336 ComponentName componentName = iterator.next(); 337 String componentPackage = componentName.getPackageName(); 338 for (String stoppedPackage : stoppedPackages) { 339 if (componentPackage.equals(stoppedPackage)) { 340 if (!doit) { 341 return true; 342 } 343 stoppedSomePackages = true; 344 break; 345 } 346 } 347 } 348 if (stoppedSomePackages) { 349 userState.updateIfNeededLocked(); 350 } 351 return false; 352 } 353 } 354 355 private void persistComponentNamesToSettingLocked(String settingName, 356 Set<ComponentName> componentNames, int userId) { 357 StringBuilder builder = new StringBuilder(); 358 for (ComponentName componentName : componentNames) { 359 if (builder.length() > 0) { 360 builder.append(COMPONENT_NAME_SEPARATOR); 361 } 362 builder.append(componentName.flattenToShortString()); 363 } 364 Settings.Secure.putStringForUser(mContext.getContentResolver(), 365 settingName, builder.toString(), userId); 366 } 367 }; 368 369 // package changes 370 monitor.register(mContext, BackgroundThread.getHandler().getLooper(), 371 UserHandle.ALL, true); 372 373 // user changes 374 IntentFilter intentFilter = new IntentFilter(); 375 intentFilter.addAction(Intent.ACTION_USER_SWITCHED); 376 377 mContext.registerReceiverAsUser(new BroadcastReceiver() { 378 @Override 379 public void onReceive(Context context, Intent intent) { 380 String action = intent.getAction(); 381 if (Intent.ACTION_USER_SWITCHED.equals(action)) { 382 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); 383 } else if (Intent.ACTION_USER_REMOVED.equals(action)) { 384 removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); 385 } 386 } 387 }, UserHandle.ALL, intentFilter, null, BackgroundThread.getHandler()); 388 } 389 390 private UserState getCurrentUserStateLocked() { 391 return getOrCreateUserStateLocked(mCurrentUserId); 392 } 393 394 private UserState getOrCreateUserStateLocked(int userId) { 395 UserState userState = mUserStates.get(userId); 396 if (userState == null) { 397 userState = new UserState(mContext, userId, mLock); 398 mUserStates.put(userId, userState); 399 } 400 return userState; 401 } 402 403 private void switchUser(int newUserId) { 404 synchronized (mLock) { 405 if (newUserId == mCurrentUserId) { 406 return; 407 } 408 mCurrentUserId = newUserId; 409 UserState userState = getCurrentUserStateLocked(); 410 userState.updateIfNeededLocked(); 411 userState.getSpoolerLocked().start(); 412 } 413 } 414 415 private void removeUser(int removedUserId) { 416 synchronized (mLock) { 417 UserState userState = mUserStates.get(removedUserId); 418 if (userState != null) { 419 userState.destroyLocked(); 420 mUserStates.remove(removedUserId); 421 } 422 } 423 } 424 425 private int resolveCallingAppEnforcingPermissions(int appId) { 426 final int callingUid = Binder.getCallingUid(); 427 if (callingUid == 0 || callingUid == Process.SYSTEM_UID 428 || callingUid == Process.SHELL_UID) { 429 return appId; 430 } 431 final int callingAppId = UserHandle.getAppId(callingUid); 432 if (appId == callingAppId) { 433 return appId; 434 } 435 if (mContext.checkCallingPermission(Manifest.permission.ACCESS_ALL_PRINT_JOBS) 436 != PackageManager.PERMISSION_GRANTED) { 437 throw new SecurityException("Call from app " + callingAppId + " as app " 438 + appId + " without permission ACCESS_ALL_PRINT_JOBS"); 439 } 440 return appId; 441 } 442 443 private int resolveCallingUserEnforcingPermissions(int userId) { 444 final int callingUid = Binder.getCallingUid(); 445 if (callingUid == 0 || callingUid == Process.SYSTEM_UID 446 || callingUid == Process.SHELL_UID) { 447 return userId; 448 } 449 final int callingUserId = UserHandle.getUserId(callingUid); 450 if (callingUserId == userId) { 451 return userId; 452 } 453 if (mContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL) 454 != PackageManager.PERMISSION_GRANTED 455 || mContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS) 456 != PackageManager.PERMISSION_GRANTED) { 457 if (userId == UserHandle.USER_CURRENT_OR_SELF) { 458 return callingUserId; 459 } 460 throw new SecurityException("Call from user " + callingUserId + " as user " 461 + userId + " without permission INTERACT_ACROSS_USERS or " 462 + "INTERACT_ACROSS_USERS_FULL not allowed."); 463 } 464 if (userId == UserHandle.USER_CURRENT || userId == UserHandle.USER_CURRENT_OR_SELF) { 465 return mCurrentUserId; 466 } 467 throw new IllegalArgumentException("Calling user can be changed to only " 468 + "UserHandle.USER_CURRENT or UserHandle.USER_CURRENT_OR_SELF."); 469 } 470} 471