Home | History | Annotate | Download | only in print
      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.ActivityManager;
     21 import android.app.ActivityManagerNative;
     22 import android.app.Notification;
     23 import android.app.NotificationManager;
     24 import android.app.PendingIntent;
     25 import android.content.ComponentName;
     26 import android.content.Context;
     27 import android.content.Intent;
     28 import android.content.pm.PackageManager;
     29 import android.content.pm.PackageManager.NameNotFoundException;
     30 import android.content.pm.ResolveInfo;
     31 import android.content.pm.ServiceInfo;
     32 import android.content.pm.UserInfo;
     33 import android.database.ContentObserver;
     34 import android.net.Uri;
     35 import android.os.Binder;
     36 import android.os.Bundle;
     37 import android.os.Process;
     38 import android.os.RemoteException;
     39 import android.os.UserHandle;
     40 import android.os.UserManager;
     41 import android.print.IPrintDocumentAdapter;
     42 import android.print.IPrintJobStateChangeListener;
     43 import android.print.IPrintManager;
     44 import android.print.IPrinterDiscoveryObserver;
     45 import android.print.PrintAttributes;
     46 import android.print.PrintJobId;
     47 import android.print.PrintJobInfo;
     48 import android.print.PrinterId;
     49 import android.printservice.PrintServiceInfo;
     50 import android.provider.Settings;
     51 import android.text.TextUtils;
     52 import android.util.SparseArray;
     53 
     54 import com.android.internal.R;
     55 import com.android.internal.content.PackageMonitor;
     56 import com.android.internal.os.BackgroundThread;
     57 import com.android.server.SystemService;
     58 
     59 import java.io.FileDescriptor;
     60 import java.io.PrintWriter;
     61 import java.util.Iterator;
     62 import java.util.List;
     63 import java.util.Set;
     64 
     65 /**
     66  * SystemService wrapper for the PrintManager implementation. Publishes
     67  * Context.PRINT_SERVICE.
     68  * PrintManager implementation is contained within.
     69  */
     70 
     71 public final class PrintManagerService extends SystemService {
     72     private final PrintManagerImpl mPrintManagerImpl;
     73 
     74     public PrintManagerService(Context context) {
     75         super(context);
     76         mPrintManagerImpl = new PrintManagerImpl(context);
     77     }
     78 
     79     @Override
     80     public void onStart() {
     81         publishBinderService(Context.PRINT_SERVICE, mPrintManagerImpl);
     82     }
     83 
     84     @Override
     85     public void onStartUser(int userHandle) {
     86         mPrintManagerImpl.handleUserStarted(userHandle);
     87     }
     88 
     89     @Override
     90     public void onStopUser(int userHandle) {
     91         mPrintManagerImpl.handleUserStopped(userHandle);
     92     }
     93 
     94     class PrintManagerImpl extends IPrintManager.Stub {
     95         private static final char COMPONENT_NAME_SEPARATOR = ':';
     96 
     97         private static final String EXTRA_PRINT_SERVICE_COMPONENT_NAME =
     98                 "EXTRA_PRINT_SERVICE_COMPONENT_NAME";
     99 
    100         private static final int BACKGROUND_USER_ID = -10;
    101 
    102         private final Object mLock = new Object();
    103 
    104         private final Context mContext;
    105 
    106         private final UserManager mUserManager;
    107 
    108         private final SparseArray<UserState> mUserStates = new SparseArray<>();
    109 
    110         PrintManagerImpl(Context context) {
    111             mContext = context;
    112             mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
    113             registerContentObservers();
    114             registerBroadcastReceivers();
    115         }
    116 
    117         @Override
    118         public Bundle print(String printJobName, IPrintDocumentAdapter adapter,
    119                 PrintAttributes attributes, String packageName, int appId, int userId) {
    120             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    121             final int resolvedAppId;
    122             final UserState userState;
    123             final String resolvedPackageName;
    124             synchronized (mLock) {
    125                 // Only the current group members can start new print jobs.
    126                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    127                     return null;
    128                 }
    129                 resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
    130                 resolvedPackageName = resolveCallingPackageNameEnforcingSecurity(packageName);
    131                 userState = getOrCreateUserStateLocked(resolvedUserId);
    132             }
    133             final long identity = Binder.clearCallingIdentity();
    134             try {
    135                 return userState.print(printJobName, adapter, attributes,
    136                         resolvedPackageName, resolvedAppId);
    137             } finally {
    138                 Binder.restoreCallingIdentity(identity);
    139             }
    140         }
    141 
    142         @Override
    143         public List<PrintJobInfo> getPrintJobInfos(int appId, int userId) {
    144             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    145             final int resolvedAppId;
    146             final UserState userState;
    147             synchronized (mLock) {
    148                 // Only the current group members can query for state of print jobs.
    149                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    150                     return null;
    151                 }
    152                 resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
    153                 userState = getOrCreateUserStateLocked(resolvedUserId);
    154             }
    155             final long identity = Binder.clearCallingIdentity();
    156             try {
    157                 return userState.getPrintJobInfos(resolvedAppId);
    158             } finally {
    159                 Binder.restoreCallingIdentity(identity);
    160             }
    161         }
    162 
    163         @Override
    164         public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId, int userId) {
    165             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    166             final int resolvedAppId;
    167             final UserState userState;
    168             synchronized (mLock) {
    169                 // Only the current group members can query for state of a print job.
    170                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    171                     return null;
    172                 }
    173                 resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
    174                 userState = getOrCreateUserStateLocked(resolvedUserId);
    175             }
    176             final long identity = Binder.clearCallingIdentity();
    177             try {
    178                 return userState.getPrintJobInfo(printJobId, resolvedAppId);
    179             } finally {
    180                 Binder.restoreCallingIdentity(identity);
    181             }
    182         }
    183 
    184         @Override
    185         public void cancelPrintJob(PrintJobId printJobId, int appId, int userId) {
    186             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    187             final int resolvedAppId;
    188             final UserState userState;
    189             synchronized (mLock) {
    190                 // Only the current group members can cancel a print job.
    191                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    192                     return;
    193                 }
    194                 resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
    195                 userState = getOrCreateUserStateLocked(resolvedUserId);
    196             }
    197             final long identity = Binder.clearCallingIdentity();
    198             try {
    199                 userState.cancelPrintJob(printJobId, resolvedAppId);
    200             } finally {
    201                 Binder.restoreCallingIdentity(identity);
    202             }
    203         }
    204 
    205         @Override
    206         public void restartPrintJob(PrintJobId printJobId, int appId, int userId) {
    207             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    208             final int resolvedAppId;
    209             final UserState userState;
    210             synchronized (mLock) {
    211                 // Only the current group members can restart a print job.
    212                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    213                     return;
    214                 }
    215                 resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
    216                 userState = getOrCreateUserStateLocked(resolvedUserId);
    217             }
    218             final long identity = Binder.clearCallingIdentity();
    219             try {
    220                 userState.restartPrintJob(printJobId, resolvedAppId);
    221             } finally {
    222                 Binder.restoreCallingIdentity(identity);
    223             }
    224         }
    225 
    226         @Override
    227         public List<PrintServiceInfo> getEnabledPrintServices(int userId) {
    228             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    229             final UserState userState;
    230             synchronized (mLock) {
    231                 // Only the current group members can get enabled services.
    232                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    233                     return null;
    234                 }
    235                 userState = getOrCreateUserStateLocked(resolvedUserId);
    236             }
    237             final long identity = Binder.clearCallingIdentity();
    238             try {
    239                 return userState.getEnabledPrintServices();
    240             } finally {
    241                 Binder.restoreCallingIdentity(identity);
    242             }
    243         }
    244 
    245         @Override
    246         public List<PrintServiceInfo> getInstalledPrintServices(int userId) {
    247             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    248             final UserState userState;
    249             synchronized (mLock) {
    250                 // Only the current group members can get installed services.
    251                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    252                     return null;
    253                 }
    254                 userState = getOrCreateUserStateLocked(resolvedUserId);
    255             }
    256             final long identity = Binder.clearCallingIdentity();
    257             try {
    258                 return userState.getInstalledPrintServices();
    259             } finally {
    260                 Binder.restoreCallingIdentity(identity);
    261             }
    262         }
    263 
    264         @Override
    265         public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
    266                 int userId) {
    267             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    268             final UserState userState;
    269             synchronized (mLock) {
    270                 // Only the current group members can create a discovery session.
    271                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    272                     return;
    273                 }
    274                 userState = getOrCreateUserStateLocked(resolvedUserId);
    275             }
    276             final long identity = Binder.clearCallingIdentity();
    277             try {
    278                 userState.createPrinterDiscoverySession(observer);
    279             } finally {
    280                 Binder.restoreCallingIdentity(identity);
    281             }
    282         }
    283 
    284         @Override
    285         public void destroyPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
    286                 int userId) {
    287             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    288             final UserState userState;
    289             synchronized (mLock) {
    290                 // Only the current group members can destroy a discovery session.
    291                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    292                     return;
    293                 }
    294                 userState = getOrCreateUserStateLocked(resolvedUserId);
    295             }
    296             final long identity = Binder.clearCallingIdentity();
    297             try {
    298                 userState.destroyPrinterDiscoverySession(observer);
    299             } finally {
    300                 Binder.restoreCallingIdentity(identity);
    301             }
    302         }
    303 
    304         @Override
    305         public void startPrinterDiscovery(IPrinterDiscoveryObserver observer,
    306                 List<PrinterId> priorityList, int userId) {
    307             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    308             final UserState userState;
    309             synchronized (mLock) {
    310                 // Only the current group members can start discovery.
    311                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    312                     return;
    313                 }
    314                 userState = getOrCreateUserStateLocked(resolvedUserId);
    315             }
    316             final long identity = Binder.clearCallingIdentity();
    317             try {
    318                 userState.startPrinterDiscovery(observer, priorityList);
    319             } finally {
    320                 Binder.restoreCallingIdentity(identity);
    321             }
    322         }
    323 
    324         @Override
    325         public void stopPrinterDiscovery(IPrinterDiscoveryObserver observer, int userId) {
    326             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    327             final UserState userState;
    328             synchronized (mLock) {
    329                 // Only the current group members can stop discovery.
    330                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    331                     return;
    332                 }
    333                 userState = getOrCreateUserStateLocked(resolvedUserId);
    334             }
    335             final long identity = Binder.clearCallingIdentity();
    336             try {
    337                 userState.stopPrinterDiscovery(observer);
    338             } finally {
    339                 Binder.restoreCallingIdentity(identity);
    340             }
    341         }
    342 
    343         @Override
    344         public void validatePrinters(List<PrinterId> printerIds, int userId) {
    345             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    346             final UserState userState;
    347             synchronized (mLock) {
    348                 // Only the current group members can validate printers.
    349                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    350                     return;
    351                 }
    352                 userState = getOrCreateUserStateLocked(resolvedUserId);
    353             }
    354             final long identity = Binder.clearCallingIdentity();
    355             try {
    356                 userState.validatePrinters(printerIds);
    357             } finally {
    358                 Binder.restoreCallingIdentity(identity);
    359             }
    360         }
    361 
    362         @Override
    363         public void startPrinterStateTracking(PrinterId printerId, int userId) {
    364             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    365             final UserState userState;
    366             synchronized (mLock) {
    367                 // Only the current group members can start printer tracking.
    368                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    369                     return;
    370                 }
    371                 userState = getOrCreateUserStateLocked(resolvedUserId);
    372             }
    373             final long identity = Binder.clearCallingIdentity();
    374             try {
    375                 userState.startPrinterStateTracking(printerId);
    376             } finally {
    377                 Binder.restoreCallingIdentity(identity);
    378             }
    379         }
    380 
    381         @Override
    382         public void stopPrinterStateTracking(PrinterId printerId, int userId) {
    383             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    384             final UserState userState;
    385             synchronized (mLock) {
    386                 // Only the current group members can stop printer tracking.
    387                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    388                     return;
    389                 }
    390                 userState = getOrCreateUserStateLocked(resolvedUserId);
    391             }
    392             final long identity = Binder.clearCallingIdentity();
    393             try {
    394                 userState.stopPrinterStateTracking(printerId);
    395             } finally {
    396                 Binder.restoreCallingIdentity(identity);
    397             }
    398         }
    399 
    400         @Override
    401         public void addPrintJobStateChangeListener(IPrintJobStateChangeListener listener,
    402                 int appId, int userId) throws RemoteException {
    403             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    404             final int resolvedAppId;
    405             final UserState userState;
    406             synchronized (mLock) {
    407                 // Only the current group members can add a print job listener.
    408                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    409                     return;
    410                 }
    411                 resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
    412                 userState = getOrCreateUserStateLocked(resolvedUserId);
    413             }
    414             final long identity = Binder.clearCallingIdentity();
    415             try {
    416                 userState.addPrintJobStateChangeListener(listener, resolvedAppId);
    417             } finally {
    418                 Binder.restoreCallingIdentity(identity);
    419             }
    420         }
    421 
    422         @Override
    423         public void removePrintJobStateChangeListener(IPrintJobStateChangeListener listener,
    424                 int userId) {
    425             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    426             final UserState userState;
    427             synchronized (mLock) {
    428                 // Only the current group members can remove a print job listener.
    429                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    430                     return;
    431                 }
    432                 userState = getOrCreateUserStateLocked(resolvedUserId);
    433             }
    434             final long identity = Binder.clearCallingIdentity();
    435             try {
    436                 userState.removePrintJobStateChangeListener(listener);
    437             } finally {
    438                 Binder.restoreCallingIdentity(identity);
    439             }
    440         }
    441 
    442         @Override
    443         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    444             if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
    445                     != PackageManager.PERMISSION_GRANTED) {
    446                 pw.println("Permission Denial: can't dump PrintManager from from pid="
    447                         + Binder.getCallingPid()
    448                         + ", uid=" + Binder.getCallingUid());
    449                 return;
    450             }
    451 
    452             synchronized (mLock) {
    453                 final long identity = Binder.clearCallingIdentity();
    454                 try {
    455                     pw.println("PRINT MANAGER STATE (dumpsys print)");
    456                     final int userStateCount = mUserStates.size();
    457                     for (int i = 0; i < userStateCount; i++) {
    458                         UserState userState = mUserStates.valueAt(i);
    459                         userState.dump(fd, pw, "");
    460                         pw.println();
    461                     }
    462                 } finally {
    463                     Binder.restoreCallingIdentity(identity);
    464                 }
    465             }
    466         }
    467 
    468         private void registerContentObservers() {
    469             final Uri enabledPrintServicesUri = Settings.Secure.getUriFor(
    470                     Settings.Secure.ENABLED_PRINT_SERVICES);
    471             ContentObserver observer = new ContentObserver(BackgroundThread.getHandler()) {
    472                 @Override
    473                 public void onChange(boolean selfChange, Uri uri, int userId) {
    474                     if (enabledPrintServicesUri.equals(uri)) {
    475                         synchronized (mLock) {
    476                             if (userId != UserHandle.USER_ALL) {
    477                                 UserState userState = getOrCreateUserStateLocked(userId);
    478                                 userState.updateIfNeededLocked();
    479                             } else {
    480                                 final int userCount = mUserStates.size();
    481                                 for (int i = 0; i < userCount; i++) {
    482                                     UserState userState = mUserStates.valueAt(i);
    483                                     userState.updateIfNeededLocked();
    484                                 }
    485                             }
    486                         }
    487                     }
    488                 }
    489             };
    490 
    491             mContext.getContentResolver().registerContentObserver(enabledPrintServicesUri,
    492                     false, observer, UserHandle.USER_ALL);
    493         }
    494 
    495         private void registerBroadcastReceivers() {
    496             PackageMonitor monitor = new PackageMonitor() {
    497                 @Override
    498                 public void onPackageModified(String packageName) {
    499                     synchronized (mLock) {
    500                         // A background user/profile's print jobs are running but there is
    501                         // no UI shown. Hence, if the packages of such a user change we need
    502                         // to handle it as the change may affect ongoing print jobs.
    503                         boolean servicesChanged = false;
    504                         UserState userState = getOrCreateUserStateLocked(getChangingUserId());
    505                         Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
    506                         while (iterator.hasNext()) {
    507                             ComponentName componentName = iterator.next();
    508                             if (packageName.equals(componentName.getPackageName())) {
    509                                 servicesChanged = true;
    510                             }
    511                         }
    512                         if (servicesChanged) {
    513                             userState.updateIfNeededLocked();
    514                         }
    515                     }
    516                 }
    517 
    518                 @Override
    519                 public void onPackageRemoved(String packageName, int uid) {
    520                     synchronized (mLock) {
    521                         // A background user/profile's print jobs are running but there is
    522                         // no UI shown. Hence, if the packages of such a user change we need
    523                         // to handle it as the change may affect ongoing print jobs.
    524                         boolean servicesRemoved = false;
    525                         UserState userState = getOrCreateUserStateLocked(getChangingUserId());
    526                         Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
    527                         while (iterator.hasNext()) {
    528                             ComponentName componentName = iterator.next();
    529                             if (packageName.equals(componentName.getPackageName())) {
    530                                 iterator.remove();
    531                                 servicesRemoved = true;
    532                             }
    533                         }
    534                         if (servicesRemoved) {
    535                             persistComponentNamesToSettingLocked(
    536                                     Settings.Secure.ENABLED_PRINT_SERVICES,
    537                                     userState.getEnabledServices(), getChangingUserId());
    538                             userState.updateIfNeededLocked();
    539                         }
    540                     }
    541                 }
    542 
    543                 @Override
    544                 public boolean onHandleForceStop(Intent intent, String[] stoppedPackages,
    545                         int uid, boolean doit) {
    546                     synchronized (mLock) {
    547                         // A background user/profile's print jobs are running but there is
    548                         // no UI shown. Hence, if the packages of such a user change we need
    549                         // to handle it as the change may affect ongoing print jobs.
    550                         UserState userState = getOrCreateUserStateLocked(getChangingUserId());
    551                         boolean stoppedSomePackages = false;
    552                         Iterator<ComponentName> iterator = userState.getEnabledServices()
    553                                 .iterator();
    554                         while (iterator.hasNext()) {
    555                             ComponentName componentName = iterator.next();
    556                             String componentPackage = componentName.getPackageName();
    557                             for (String stoppedPackage : stoppedPackages) {
    558                                 if (componentPackage.equals(stoppedPackage)) {
    559                                     if (!doit) {
    560                                         return true;
    561                                     }
    562                                     stoppedSomePackages = true;
    563                                     break;
    564                                 }
    565                             }
    566                         }
    567                         if (stoppedSomePackages) {
    568                             userState.updateIfNeededLocked();
    569                         }
    570                         return false;
    571                     }
    572                 }
    573 
    574                 @Override
    575                 public void onPackageAdded(String packageName, int uid) {
    576                     // A background user/profile's print jobs are running but there is
    577                     // no UI shown. Hence, if the packages of such a user change we need
    578                     // to handle it as the change may affect ongoing print jobs.
    579                     Intent intent = new Intent(android.printservice.PrintService.SERVICE_INTERFACE);
    580                     intent.setPackage(packageName);
    581 
    582                     List<ResolveInfo> installedServices = mContext.getPackageManager()
    583                             .queryIntentServicesAsUser(intent, PackageManager.GET_SERVICES,
    584                                     getChangingUserId());
    585 
    586                     if (installedServices == null) {
    587                         return;
    588                     }
    589 
    590                     final int installedServiceCount = installedServices.size();
    591                     for (int i = 0; i < installedServiceCount; i++) {
    592                         ServiceInfo serviceInfo = installedServices.get(i).serviceInfo;
    593                         ComponentName component = new ComponentName(serviceInfo.packageName,
    594                                 serviceInfo.name);
    595                         String label = serviceInfo.loadLabel(mContext.getPackageManager())
    596                                 .toString();
    597                         showEnableInstalledPrintServiceNotification(component, label,
    598                                 getChangingUserId());
    599                     }
    600                 }
    601 
    602                 private void persistComponentNamesToSettingLocked(String settingName,
    603                         Set<ComponentName> componentNames, int userId) {
    604                     StringBuilder builder = new StringBuilder();
    605                     for (ComponentName componentName : componentNames) {
    606                         if (builder.length() > 0) {
    607                             builder.append(COMPONENT_NAME_SEPARATOR);
    608                         }
    609                         builder.append(componentName.flattenToShortString());
    610                     }
    611                     Settings.Secure.putStringForUser(mContext.getContentResolver(),
    612                             settingName, builder.toString(), userId);
    613                 }
    614             };
    615 
    616             // package changes
    617             monitor.register(mContext, BackgroundThread.getHandler().getLooper(),
    618                     UserHandle.ALL, true);
    619         }
    620 
    621         private UserState getOrCreateUserStateLocked(int userId) {
    622             UserState userState = mUserStates.get(userId);
    623             if (userState == null) {
    624                 userState = new UserState(mContext, userId, mLock);
    625                 mUserStates.put(userId, userState);
    626             }
    627             return userState;
    628         }
    629 
    630         private void handleUserStarted(final int userId) {
    631             // This code will touch the remote print spooler which
    632             // must be called off the main thread, so post the work.
    633             BackgroundThread.getHandler().post(new Runnable() {
    634                 @Override
    635                 public void run() {
    636                     UserState userState;
    637                     synchronized (mLock) {
    638                         userState = getOrCreateUserStateLocked(userId);
    639                         userState.updateIfNeededLocked();
    640                     }
    641                     // This is the first time we switch to this user after boot, so
    642                     // now is the time to remove obsolete print jobs since they
    643                     // are from the last boot and no application would query them.
    644                     userState.removeObsoletePrintJobs();
    645                 }
    646             });
    647         }
    648 
    649         private void handleUserStopped(final int userId) {
    650             // This code will touch the remote print spooler which
    651             // must be called off the main thread, so post the work.
    652             BackgroundThread.getHandler().post(new Runnable() {
    653                 @Override
    654                 public void run() {
    655                     synchronized (mLock) {
    656                         UserState userState = mUserStates.get(userId);
    657                         if (userState != null) {
    658                             userState.destroyLocked();
    659                             mUserStates.remove(userId);
    660                         }
    661                     }
    662                 }
    663             });
    664         }
    665 
    666         private int resolveCallingProfileParentLocked(int userId) {
    667             if (userId != getCurrentUserId()) {
    668                 final long identity = Binder.clearCallingIdentity();
    669                 try {
    670                     UserInfo parent = mUserManager.getProfileParent(userId);
    671                     if (parent != null) {
    672                         return parent.getUserHandle().getIdentifier();
    673                     } else {
    674                         return BACKGROUND_USER_ID;
    675                     }
    676                 } finally {
    677                     Binder.restoreCallingIdentity(identity);
    678                 }
    679             }
    680             return userId;
    681         }
    682 
    683         private int resolveCallingAppEnforcingPermissions(int appId) {
    684             final int callingUid = Binder.getCallingUid();
    685             if (callingUid == 0 || callingUid == Process.SYSTEM_UID
    686                     || callingUid == Process.SHELL_UID) {
    687                 return appId;
    688             }
    689             final int callingAppId = UserHandle.getAppId(callingUid);
    690             if (appId == callingAppId) {
    691                 return appId;
    692             }
    693             if (mContext.checkCallingPermission(
    694                     "com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS")
    695                     != PackageManager.PERMISSION_GRANTED) {
    696                 throw new SecurityException("Call from app " + callingAppId + " as app "
    697                         + appId + " without com.android.printspooler.permission"
    698                         + ".ACCESS_ALL_PRINT_JOBS");
    699             }
    700             return appId;
    701         }
    702 
    703         private int resolveCallingUserEnforcingPermissions(int userId) {
    704             try {
    705                 return ActivityManagerNative.getDefault().handleIncomingUser(Binder.getCallingPid(),
    706                         Binder.getCallingUid(), userId, true, true, "", null);
    707             } catch (RemoteException re) {
    708                 // Shouldn't happen, local.
    709             }
    710             return userId;
    711         }
    712 
    713         private String resolveCallingPackageNameEnforcingSecurity(String packageName) {
    714             if (TextUtils.isEmpty(packageName)) {
    715                 return null;
    716             }
    717             String[] packages = mContext.getPackageManager().getPackagesForUid(
    718                     Binder.getCallingUid());
    719             final int packageCount = packages.length;
    720             for (int i = 0; i < packageCount; i++) {
    721                 if (packageName.equals(packages[i])) {
    722                     return packageName;
    723                 }
    724             }
    725             return null;
    726         }
    727 
    728         private int getCurrentUserId () {
    729             final long identity = Binder.clearCallingIdentity();
    730             try {
    731                 return ActivityManager.getCurrentUser();
    732             } finally {
    733                 Binder.restoreCallingIdentity(identity);
    734             }
    735         }
    736 
    737         private void showEnableInstalledPrintServiceNotification(ComponentName component,
    738                 String label, int userId) {
    739             UserHandle userHandle = new UserHandle(userId);
    740 
    741             Intent intent = new Intent(Settings.ACTION_PRINT_SETTINGS);
    742             intent.putExtra(EXTRA_PRINT_SERVICE_COMPONENT_NAME, component.flattenToString());
    743 
    744             PendingIntent pendingIntent = PendingIntent.getActivityAsUser(mContext, 0, intent,
    745                     PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT, null,
    746                     userHandle);
    747 
    748             Context builderContext = mContext;
    749             try {
    750                 builderContext = mContext.createPackageContextAsUser(mContext.getPackageName(), 0,
    751                         userHandle);
    752             } catch (NameNotFoundException e) {
    753                 // Ignore can't find the package the system is running as.
    754             }
    755             Notification.Builder builder = new Notification.Builder(builderContext)
    756                     .setSmallIcon(R.drawable.ic_print)
    757                     .setContentTitle(mContext.getString(R.string.print_service_installed_title,
    758                             label))
    759                     .setContentText(mContext.getString(R.string.print_service_installed_message))
    760                     .setContentIntent(pendingIntent)
    761                     .setWhen(System.currentTimeMillis())
    762                     .setAutoCancel(true)
    763                     .setShowWhen(true)
    764                     .setColor(mContext.getResources().getColor(
    765                             com.android.internal.R.color.system_notification_accent_color));
    766 
    767             NotificationManager notificationManager = (NotificationManager) mContext
    768                     .getSystemService(Context.NOTIFICATION_SERVICE);
    769 
    770             String notificationTag = getClass().getName() + ":" + component.flattenToString();
    771             notificationManager.notifyAsUser(notificationTag, 0, builder.build(),
    772                     userHandle);
    773         }
    774     }
    775 }
    776