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 static android.content.pm.PackageManager.GET_SERVICES;
     20 import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
     21 
     22 import android.annotation.NonNull;
     23 import android.app.ActivityManager;
     24 import android.content.ComponentName;
     25 import android.content.Context;
     26 import android.content.Intent;
     27 import android.content.pm.PackageManager;
     28 import android.content.pm.ResolveInfo;
     29 import android.content.pm.UserInfo;
     30 import android.database.ContentObserver;
     31 import android.graphics.drawable.Icon;
     32 import android.net.Uri;
     33 import android.os.Binder;
     34 import android.os.Bundle;
     35 import android.os.Process;
     36 import android.os.RemoteException;
     37 import android.os.UserHandle;
     38 import android.os.UserManager;
     39 import android.print.IPrintDocumentAdapter;
     40 import android.print.IPrintJobStateChangeListener;
     41 import android.print.IPrintManager;
     42 import android.print.IPrintServicesChangeListener;
     43 import android.print.IPrinterDiscoveryObserver;
     44 import android.print.PrintAttributes;
     45 import android.print.PrintJobId;
     46 import android.print.PrintJobInfo;
     47 import android.print.PrintManager;
     48 import android.print.PrinterId;
     49 import android.printservice.PrintServiceInfo;
     50 import android.printservice.recommendation.IRecommendationsChangeListener;
     51 import android.printservice.recommendation.RecommendationInfo;
     52 import android.provider.Settings;
     53 import android.util.Log;
     54 import android.util.SparseArray;
     55 
     56 import com.android.internal.content.PackageMonitor;
     57 import com.android.internal.os.BackgroundThread;
     58 import com.android.internal.util.DumpUtils;
     59 import com.android.internal.util.Preconditions;
     60 import com.android.server.SystemService;
     61 
     62 import java.io.FileDescriptor;
     63 import java.io.PrintWriter;
     64 import java.util.Iterator;
     65 import java.util.List;
     66 
     67 /**
     68  * SystemService wrapper for the PrintManager implementation. Publishes
     69  * Context.PRINT_SERVICE.
     70  * PrintManager implementation is contained within.
     71  */
     72 public final class PrintManagerService extends SystemService {
     73     private static final String LOG_TAG = "PrintManagerService";
     74 
     75     private final PrintManagerImpl mPrintManagerImpl;
     76 
     77     public PrintManagerService(Context context) {
     78         super(context);
     79         mPrintManagerImpl = new PrintManagerImpl(context);
     80     }
     81 
     82     @Override
     83     public void onStart() {
     84         publishBinderService(Context.PRINT_SERVICE, mPrintManagerImpl);
     85     }
     86 
     87     @Override
     88     public void onUnlockUser(int userHandle) {
     89         mPrintManagerImpl.handleUserUnlocked(userHandle);
     90     }
     91 
     92     @Override
     93     public void onStopUser(int userHandle) {
     94         mPrintManagerImpl.handleUserStopped(userHandle);
     95     }
     96 
     97     class PrintManagerImpl extends IPrintManager.Stub {
     98         private static final int BACKGROUND_USER_ID = -10;
     99 
    100         private final Object mLock = new Object();
    101 
    102         private final Context mContext;
    103 
    104         private final UserManager mUserManager;
    105 
    106         private final SparseArray<UserState> mUserStates = new SparseArray<>();
    107 
    108         PrintManagerImpl(Context context) {
    109             mContext = context;
    110             mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
    111             registerContentObservers();
    112             registerBroadcastReceivers();
    113         }
    114 
    115         @Override
    116         public Bundle print(String printJobName, IPrintDocumentAdapter adapter,
    117                 PrintAttributes attributes, String packageName, int appId, int userId) {
    118             printJobName = Preconditions.checkStringNotEmpty(printJobName);
    119             adapter = Preconditions.checkNotNull(adapter);
    120             packageName = Preconditions.checkStringNotEmpty(packageName);
    121 
    122             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    123             final int resolvedAppId;
    124             final UserState userState;
    125             final String resolvedPackageName;
    126             synchronized (mLock) {
    127                 // Only the current group members can start new print jobs.
    128                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    129                     return null;
    130                 }
    131                 resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
    132                 resolvedPackageName = resolveCallingPackageNameEnforcingSecurity(packageName);
    133                 userState = getOrCreateUserStateLocked(resolvedUserId, false);
    134             }
    135             final long identity = Binder.clearCallingIdentity();
    136             try {
    137                 return userState.print(printJobName, adapter, attributes,
    138                         resolvedPackageName, resolvedAppId);
    139             } finally {
    140                 Binder.restoreCallingIdentity(identity);
    141             }
    142         }
    143 
    144         @Override
    145         public List<PrintJobInfo> getPrintJobInfos(int appId, int userId) {
    146             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    147             final int resolvedAppId;
    148             final UserState userState;
    149             synchronized (mLock) {
    150                 // Only the current group members can query for state of print jobs.
    151                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    152                     return null;
    153                 }
    154                 resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
    155                 userState = getOrCreateUserStateLocked(resolvedUserId, false);
    156             }
    157             final long identity = Binder.clearCallingIdentity();
    158             try {
    159                 return userState.getPrintJobInfos(resolvedAppId);
    160             } finally {
    161                 Binder.restoreCallingIdentity(identity);
    162             }
    163         }
    164 
    165         @Override
    166         public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId, int userId) {
    167             if (printJobId == null) {
    168                 return null;
    169             }
    170 
    171             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    172             final int resolvedAppId;
    173             final UserState userState;
    174             synchronized (mLock) {
    175                 // Only the current group members can query for state of a print job.
    176                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    177                     return null;
    178                 }
    179                 resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
    180                 userState = getOrCreateUserStateLocked(resolvedUserId, false);
    181             }
    182             final long identity = Binder.clearCallingIdentity();
    183             try {
    184                 return userState.getPrintJobInfo(printJobId, resolvedAppId);
    185             } finally {
    186                 Binder.restoreCallingIdentity(identity);
    187             }
    188         }
    189 
    190         @Override
    191         public Icon getCustomPrinterIcon(PrinterId printerId, int userId) {
    192             printerId = Preconditions.checkNotNull(printerId);
    193 
    194             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    195             final UserState userState;
    196             synchronized (mLock) {
    197                 // Only the current group members can get the printer icons.
    198                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    199                     return null;
    200                 }
    201                 userState = getOrCreateUserStateLocked(resolvedUserId, false);
    202             }
    203             final long identity = Binder.clearCallingIdentity();
    204             try {
    205                 return userState.getCustomPrinterIcon(printerId);
    206             } finally {
    207                 Binder.restoreCallingIdentity(identity);
    208             }
    209         }
    210 
    211         @Override
    212         public void cancelPrintJob(PrintJobId printJobId, int appId, int userId) {
    213             if (printJobId == null) {
    214                 return;
    215             }
    216 
    217             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    218             final int resolvedAppId;
    219             final UserState userState;
    220             synchronized (mLock) {
    221                 // Only the current group members can cancel a print job.
    222                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    223                     return;
    224                 }
    225                 resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
    226                 userState = getOrCreateUserStateLocked(resolvedUserId, false);
    227             }
    228             final long identity = Binder.clearCallingIdentity();
    229             try {
    230                 userState.cancelPrintJob(printJobId, resolvedAppId);
    231             } finally {
    232                 Binder.restoreCallingIdentity(identity);
    233             }
    234         }
    235 
    236         @Override
    237         public void restartPrintJob(PrintJobId printJobId, int appId, int userId) {
    238             if (printJobId == null) {
    239                 return;
    240             }
    241 
    242             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    243             final int resolvedAppId;
    244             final UserState userState;
    245             synchronized (mLock) {
    246                 // Only the current group members can restart a print job.
    247                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    248                     return;
    249                 }
    250                 resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
    251                 userState = getOrCreateUserStateLocked(resolvedUserId, false);
    252             }
    253             final long identity = Binder.clearCallingIdentity();
    254             try {
    255                 userState.restartPrintJob(printJobId, resolvedAppId);
    256             } finally {
    257                 Binder.restoreCallingIdentity(identity);
    258             }
    259         }
    260 
    261         @Override
    262         public List<PrintServiceInfo> getPrintServices(int selectionFlags, int userId) {
    263             Preconditions.checkFlagsArgument(selectionFlags,
    264                     PrintManager.DISABLED_SERVICES | PrintManager.ENABLED_SERVICES);
    265 
    266             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    267             final UserState userState;
    268             synchronized (mLock) {
    269                 // Only the current group members can get print services.
    270                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    271                     return null;
    272                 }
    273                 userState = getOrCreateUserStateLocked(resolvedUserId, false);
    274             }
    275             final long identity = Binder.clearCallingIdentity();
    276             try {
    277                 return userState.getPrintServices(selectionFlags);
    278             } finally {
    279                 Binder.restoreCallingIdentity(identity);
    280             }
    281         }
    282 
    283         @Override
    284         public void setPrintServiceEnabled(ComponentName service, boolean isEnabled, int userId) {
    285             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    286             final int appId = UserHandle.getAppId(Binder.getCallingUid());
    287 
    288             try {
    289                 if (appId != Process.SYSTEM_UID && appId != UserHandle.getAppId(
    290                         mContext.getPackageManager().getPackageUidAsUser(
    291                                 PrintManager.PRINT_SPOOLER_PACKAGE_NAME, resolvedUserId))) {
    292                     throw new SecurityException("Only system and print spooler can call this");
    293                 }
    294             } catch (PackageManager.NameNotFoundException e) {
    295                 Log.e(LOG_TAG, "Could not verify caller", e);
    296                 return;
    297             }
    298 
    299             service = Preconditions.checkNotNull(service);
    300 
    301             final UserState userState;
    302             synchronized (mLock) {
    303                 // Only the current group members can enable / disable services.
    304                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    305                     return;
    306                 }
    307                 userState = getOrCreateUserStateLocked(resolvedUserId, false);
    308             }
    309             final long identity = Binder.clearCallingIdentity();
    310             try {
    311                 userState.setPrintServiceEnabled(service, isEnabled);
    312             } finally {
    313                 Binder.restoreCallingIdentity(identity);
    314             }
    315         }
    316 
    317         @Override
    318         public List<RecommendationInfo> getPrintServiceRecommendations(int userId) {
    319             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    320             final UserState userState;
    321             synchronized (mLock) {
    322                 // Only the current group members can get print service recommendations.
    323                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    324                     return null;
    325                 }
    326                 userState = getOrCreateUserStateLocked(resolvedUserId, false);
    327             }
    328             final long identity = Binder.clearCallingIdentity();
    329             try {
    330                 return userState.getPrintServiceRecommendations();
    331             } finally {
    332                 Binder.restoreCallingIdentity(identity);
    333             }
    334         }
    335 
    336         @Override
    337         public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
    338                 int userId) {
    339             observer = Preconditions.checkNotNull(observer);
    340 
    341             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    342             final UserState userState;
    343             synchronized (mLock) {
    344                 // Only the current group members can create a discovery session.
    345                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    346                     return;
    347                 }
    348                 userState = getOrCreateUserStateLocked(resolvedUserId, false);
    349             }
    350             final long identity = Binder.clearCallingIdentity();
    351             try {
    352                 userState.createPrinterDiscoverySession(observer);
    353             } finally {
    354                 Binder.restoreCallingIdentity(identity);
    355             }
    356         }
    357 
    358         @Override
    359         public void destroyPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
    360                 int userId) {
    361             observer = Preconditions.checkNotNull(observer);
    362 
    363             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    364             final UserState userState;
    365             synchronized (mLock) {
    366                 // Only the current group members can destroy a discovery session.
    367                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    368                     return;
    369                 }
    370                 userState = getOrCreateUserStateLocked(resolvedUserId, false);
    371             }
    372             final long identity = Binder.clearCallingIdentity();
    373             try {
    374                 userState.destroyPrinterDiscoverySession(observer);
    375             } finally {
    376                 Binder.restoreCallingIdentity(identity);
    377             }
    378         }
    379 
    380         @Override
    381         public void startPrinterDiscovery(IPrinterDiscoveryObserver observer,
    382                 List<PrinterId> priorityList, int userId) {
    383             observer = Preconditions.checkNotNull(observer);
    384             if (priorityList != null) {
    385                 priorityList = Preconditions.checkCollectionElementsNotNull(priorityList,
    386                         "PrinterId");
    387             }
    388 
    389             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    390             final UserState userState;
    391             synchronized (mLock) {
    392                 // Only the current group members can start discovery.
    393                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    394                     return;
    395                 }
    396                 userState = getOrCreateUserStateLocked(resolvedUserId, false);
    397             }
    398             final long identity = Binder.clearCallingIdentity();
    399             try {
    400                 userState.startPrinterDiscovery(observer, priorityList);
    401             } finally {
    402                 Binder.restoreCallingIdentity(identity);
    403             }
    404         }
    405 
    406         @Override
    407         public void stopPrinterDiscovery(IPrinterDiscoveryObserver observer, int userId) {
    408             observer = Preconditions.checkNotNull(observer);
    409 
    410             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    411             final UserState userState;
    412             synchronized (mLock) {
    413                 // Only the current group members can stop discovery.
    414                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    415                     return;
    416                 }
    417                 userState = getOrCreateUserStateLocked(resolvedUserId, false);
    418             }
    419             final long identity = Binder.clearCallingIdentity();
    420             try {
    421                 userState.stopPrinterDiscovery(observer);
    422             } finally {
    423                 Binder.restoreCallingIdentity(identity);
    424             }
    425         }
    426 
    427         @Override
    428         public void validatePrinters(List<PrinterId> printerIds, int userId) {
    429             printerIds = Preconditions.checkCollectionElementsNotNull(printerIds, "PrinterId");
    430 
    431             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    432             final UserState userState;
    433             synchronized (mLock) {
    434                 // Only the current group members can validate printers.
    435                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    436                     return;
    437                 }
    438                 userState = getOrCreateUserStateLocked(resolvedUserId, false);
    439             }
    440             final long identity = Binder.clearCallingIdentity();
    441             try {
    442                 userState.validatePrinters(printerIds);
    443             } finally {
    444                 Binder.restoreCallingIdentity(identity);
    445             }
    446         }
    447 
    448         @Override
    449         public void startPrinterStateTracking(PrinterId printerId, int userId) {
    450             printerId = Preconditions.checkNotNull(printerId);
    451 
    452             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    453             final UserState userState;
    454             synchronized (mLock) {
    455                 // Only the current group members can start printer tracking.
    456                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    457                     return;
    458                 }
    459                 userState = getOrCreateUserStateLocked(resolvedUserId, false);
    460             }
    461             final long identity = Binder.clearCallingIdentity();
    462             try {
    463                 userState.startPrinterStateTracking(printerId);
    464             } finally {
    465                 Binder.restoreCallingIdentity(identity);
    466             }
    467         }
    468 
    469         @Override
    470         public void stopPrinterStateTracking(PrinterId printerId, int userId) {
    471             printerId = Preconditions.checkNotNull(printerId);
    472 
    473             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    474             final UserState userState;
    475             synchronized (mLock) {
    476                 // Only the current group members can stop printer tracking.
    477                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    478                     return;
    479                 }
    480                 userState = getOrCreateUserStateLocked(resolvedUserId, false);
    481             }
    482             final long identity = Binder.clearCallingIdentity();
    483             try {
    484                 userState.stopPrinterStateTracking(printerId);
    485             } finally {
    486                 Binder.restoreCallingIdentity(identity);
    487             }
    488         }
    489 
    490         @Override
    491         public void addPrintJobStateChangeListener(IPrintJobStateChangeListener listener,
    492                 int appId, int userId) throws RemoteException {
    493             listener = Preconditions.checkNotNull(listener);
    494 
    495             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    496             final int resolvedAppId;
    497             final UserState userState;
    498             synchronized (mLock) {
    499                 // Only the current group members can add a print job listener.
    500                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    501                     return;
    502                 }
    503                 resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
    504                 userState = getOrCreateUserStateLocked(resolvedUserId, false);
    505             }
    506             final long identity = Binder.clearCallingIdentity();
    507             try {
    508                 userState.addPrintJobStateChangeListener(listener, resolvedAppId);
    509             } finally {
    510                 Binder.restoreCallingIdentity(identity);
    511             }
    512         }
    513 
    514         @Override
    515         public void removePrintJobStateChangeListener(IPrintJobStateChangeListener listener,
    516                 int userId) {
    517             listener = Preconditions.checkNotNull(listener);
    518 
    519             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    520             final UserState userState;
    521             synchronized (mLock) {
    522                 // Only the current group members can remove a print job listener.
    523                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    524                     return;
    525                 }
    526                 userState = getOrCreateUserStateLocked(resolvedUserId, false);
    527             }
    528             final long identity = Binder.clearCallingIdentity();
    529             try {
    530                 userState.removePrintJobStateChangeListener(listener);
    531             } finally {
    532                 Binder.restoreCallingIdentity(identity);
    533             }
    534         }
    535 
    536         @Override
    537         public void addPrintServicesChangeListener(IPrintServicesChangeListener listener,
    538                 int userId) throws RemoteException {
    539             listener = Preconditions.checkNotNull(listener);
    540 
    541             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    542             final UserState userState;
    543             synchronized (mLock) {
    544                 // Only the current group members can add a print services listener.
    545                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    546                     return;
    547                 }
    548                 userState = getOrCreateUserStateLocked(resolvedUserId, false);
    549             }
    550             final long identity = Binder.clearCallingIdentity();
    551             try {
    552                 userState.addPrintServicesChangeListener(listener);
    553             } finally {
    554                 Binder.restoreCallingIdentity(identity);
    555             }
    556         }
    557 
    558         @Override
    559         public void removePrintServicesChangeListener(IPrintServicesChangeListener listener,
    560                 int userId) {
    561             listener = Preconditions.checkNotNull(listener);
    562 
    563             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    564             final UserState userState;
    565             synchronized (mLock) {
    566                 // Only the current group members can remove a print services change listener.
    567                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    568                     return;
    569                 }
    570                 userState = getOrCreateUserStateLocked(resolvedUserId, false);
    571             }
    572             final long identity = Binder.clearCallingIdentity();
    573             try {
    574                 userState.removePrintServicesChangeListener(listener);
    575             } finally {
    576                 Binder.restoreCallingIdentity(identity);
    577             }
    578         }
    579 
    580         @Override
    581         public void addPrintServiceRecommendationsChangeListener(
    582                 IRecommendationsChangeListener listener, int userId)
    583                 throws RemoteException {
    584             listener = Preconditions.checkNotNull(listener);
    585 
    586             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    587             final UserState userState;
    588             synchronized (mLock) {
    589                 // Only the current group members can add a print service recommendations listener.
    590                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    591                     return;
    592                 }
    593                 userState = getOrCreateUserStateLocked(resolvedUserId, false);
    594             }
    595             final long identity = Binder.clearCallingIdentity();
    596             try {
    597                 userState.addPrintServiceRecommendationsChangeListener(listener);
    598             } finally {
    599                 Binder.restoreCallingIdentity(identity);
    600             }
    601         }
    602 
    603         @Override
    604         public void removePrintServiceRecommendationsChangeListener(
    605                 IRecommendationsChangeListener listener, int userId) {
    606             listener = Preconditions.checkNotNull(listener);
    607 
    608             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
    609             final UserState userState;
    610             synchronized (mLock) {
    611                 // Only the current group members can remove a print service recommendations
    612                 // listener.
    613                 if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
    614                     return;
    615                 }
    616                 userState = getOrCreateUserStateLocked(resolvedUserId, false);
    617             }
    618             final long identity = Binder.clearCallingIdentity();
    619             try {
    620                 userState.removePrintServiceRecommendationsChangeListener(listener);
    621             } finally {
    622                 Binder.restoreCallingIdentity(identity);
    623             }
    624         }
    625 
    626         @Override
    627         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    628             fd = Preconditions.checkNotNull(fd);
    629             pw = Preconditions.checkNotNull(pw);
    630 
    631             if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return;
    632 
    633             synchronized (mLock) {
    634                 final long identity = Binder.clearCallingIdentity();
    635                 try {
    636                     pw.println("PRINT MANAGER STATE (dumpsys print)");
    637                     final int userStateCount = mUserStates.size();
    638                     for (int i = 0; i < userStateCount; i++) {
    639                         UserState userState = mUserStates.valueAt(i);
    640                         userState.dump(fd, pw, "");
    641                         pw.println();
    642                     }
    643                 } finally {
    644                     Binder.restoreCallingIdentity(identity);
    645                 }
    646             }
    647         }
    648 
    649         private void registerContentObservers() {
    650             final Uri enabledPrintServicesUri = Settings.Secure.getUriFor(
    651                     Settings.Secure.DISABLED_PRINT_SERVICES);
    652             ContentObserver observer = new ContentObserver(BackgroundThread.getHandler()) {
    653                 @Override
    654                 public void onChange(boolean selfChange, Uri uri, int userId) {
    655                     if (enabledPrintServicesUri.equals(uri)) {
    656                         synchronized (mLock) {
    657                             final int userCount = mUserStates.size();
    658                             for (int i = 0; i < userCount; i++) {
    659                                 if (userId == UserHandle.USER_ALL
    660                                         || userId == mUserStates.keyAt(i)) {
    661                                     mUserStates.valueAt(i).updateIfNeededLocked();
    662                                 }
    663                             }
    664                         }
    665                     }
    666                 }
    667             };
    668 
    669             mContext.getContentResolver().registerContentObserver(enabledPrintServicesUri,
    670                     false, observer, UserHandle.USER_ALL);
    671         }
    672 
    673         private void registerBroadcastReceivers() {
    674             PackageMonitor monitor = new PackageMonitor() {
    675                 /**
    676                  * Checks if the package contains a print service.
    677                  *
    678                  * @param packageName The name of the package
    679                  *
    680                  * @return true iff the package contains a print service
    681                  */
    682                 private boolean hasPrintService(String packageName) {
    683                     Intent intent = new Intent(android.printservice.PrintService.SERVICE_INTERFACE);
    684                     intent.setPackage(packageName);
    685 
    686                     List<ResolveInfo> installedServices = mContext.getPackageManager()
    687                             .queryIntentServicesAsUser(intent,
    688                                     GET_SERVICES | MATCH_DEBUG_TRIAGED_MISSING,
    689                                     getChangingUserId());
    690 
    691                     return installedServices != null && !installedServices.isEmpty();
    692                 }
    693 
    694                 /**
    695                  * Checks if there is a print service currently registered for this package.
    696                  *
    697                  * @param userState The userstate for the current user
    698                  * @param packageName The name of the package
    699                  *
    700                  * @return true iff the package contained (and might still contain) a print service
    701                  */
    702                 private boolean hadPrintService(@NonNull UserState userState, String packageName) {
    703                     List<PrintServiceInfo> installedServices = userState
    704                             .getPrintServices(PrintManager.ALL_SERVICES);
    705 
    706                     if (installedServices == null) {
    707                         return false;
    708                     }
    709 
    710                     final int numInstalledServices = installedServices.size();
    711                     for (int i = 0; i < numInstalledServices; i++) {
    712                         if (installedServices.get(i).getResolveInfo().serviceInfo.packageName
    713                                 .equals(packageName)) {
    714                             return true;
    715                         }
    716                     }
    717 
    718                     return false;
    719                 }
    720 
    721                 @Override
    722                 public void onPackageModified(String packageName) {
    723                     if (!mUserManager.isUserUnlockingOrUnlocked(getChangingUserId())) return;
    724                     UserState userState = getOrCreateUserStateLocked(getChangingUserId(), false,
    725                             false /* enforceUserUnlockingOrUnlocked */);
    726 
    727                     synchronized (mLock) {
    728                         if (hadPrintService(userState, packageName)
    729                                 || hasPrintService(packageName)) {
    730                             userState.updateIfNeededLocked();
    731                         }
    732                     }
    733 
    734                     userState.prunePrintServices();
    735                 }
    736 
    737                 @Override
    738                 public void onPackageRemoved(String packageName, int uid) {
    739                     if (!mUserManager.isUserUnlockingOrUnlocked(getChangingUserId())) return;
    740                     UserState userState = getOrCreateUserStateLocked(getChangingUserId(), false,
    741                             false /* enforceUserUnlockingOrUnlocked */);
    742 
    743                     synchronized (mLock) {
    744                         if (hadPrintService(userState, packageName)) {
    745                             userState.updateIfNeededLocked();
    746                         }
    747                     }
    748 
    749                     userState.prunePrintServices();
    750                 }
    751 
    752                 @Override
    753                 public boolean onHandleForceStop(Intent intent, String[] stoppedPackages,
    754                         int uid, boolean doit) {
    755                     if (!mUserManager.isUserUnlockingOrUnlocked(getChangingUserId())) return false;
    756                     synchronized (mLock) {
    757                         // A background user/profile's print jobs are running but there is
    758                         // no UI shown. Hence, if the packages of such a user change we need
    759                         // to handle it as the change may affect ongoing print jobs.
    760                         UserState userState = getOrCreateUserStateLocked(getChangingUserId(), false,
    761                                 false /* enforceUserUnlockingOrUnlocked */);
    762                         boolean stoppedSomePackages = false;
    763 
    764                         List<PrintServiceInfo> enabledServices = userState
    765                                 .getPrintServices(PrintManager.ENABLED_SERVICES);
    766                         if (enabledServices == null) {
    767                             return false;
    768                         }
    769 
    770                         Iterator<PrintServiceInfo> iterator = enabledServices.iterator();
    771                         while (iterator.hasNext()) {
    772                             ComponentName componentName = iterator.next().getComponentName();
    773                             String componentPackage = componentName.getPackageName();
    774                             for (String stoppedPackage : stoppedPackages) {
    775                                 if (componentPackage.equals(stoppedPackage)) {
    776                                     if (!doit) {
    777                                         return true;
    778                                     }
    779                                     stoppedSomePackages = true;
    780                                     break;
    781                                 }
    782                             }
    783                         }
    784                         if (stoppedSomePackages) {
    785                             userState.updateIfNeededLocked();
    786                         }
    787                         return false;
    788                     }
    789                 }
    790 
    791                 @Override
    792                 public void onPackageAdded(String packageName, int uid) {
    793                     if (!mUserManager.isUserUnlockingOrUnlocked(getChangingUserId())) return;
    794                     synchronized (mLock) {
    795                         if (hasPrintService(packageName)) {
    796                             UserState userState = getOrCreateUserStateLocked(getChangingUserId(),
    797                                     false, false /* enforceUserUnlockingOrUnlocked */);
    798                             userState.updateIfNeededLocked();
    799                         }
    800                     }
    801                 }
    802             };
    803 
    804             // package changes
    805             monitor.register(mContext, BackgroundThread.getHandler().getLooper(),
    806                     UserHandle.ALL, true);
    807         }
    808         private UserState getOrCreateUserStateLocked(int userId, boolean lowPriority) {
    809             return getOrCreateUserStateLocked(userId, lowPriority,
    810                     true /* enforceUserUnlockingOrUnlocked */);
    811         }
    812 
    813         private UserState getOrCreateUserStateLocked(int userId, boolean lowPriority,
    814                 boolean enforceUserUnlockingOrUnlocked) {
    815             if (enforceUserUnlockingOrUnlocked && !mUserManager.isUserUnlockingOrUnlocked(userId)) {
    816                 throw new IllegalStateException(
    817                         "User " + userId + " must be unlocked for printing to be available");
    818             }
    819 
    820             UserState userState = mUserStates.get(userId);
    821             if (userState == null) {
    822                 userState = new UserState(mContext, userId, mLock, lowPriority);
    823                 mUserStates.put(userId, userState);
    824             }
    825 
    826             if (!lowPriority) {
    827                 userState.increasePriority();
    828             }
    829 
    830             return userState;
    831         }
    832 
    833         private void handleUserUnlocked(final int userId) {
    834             // This code will touch the remote print spooler which
    835             // must be called off the main thread, so post the work.
    836             BackgroundThread.getHandler().post(new Runnable() {
    837                 @Override
    838                 public void run() {
    839                     if (!mUserManager.isUserUnlockingOrUnlocked(userId)) return;
    840 
    841                     UserState userState;
    842                     synchronized (mLock) {
    843                         userState = getOrCreateUserStateLocked(userId, true,
    844                                 false /*enforceUserUnlockingOrUnlocked */);
    845                         userState.updateIfNeededLocked();
    846                     }
    847                     // This is the first time we switch to this user after boot, so
    848                     // now is the time to remove obsolete print jobs since they
    849                     // are from the last boot and no application would query them.
    850                     userState.removeObsoletePrintJobs();
    851                 }
    852             });
    853         }
    854 
    855         private void handleUserStopped(final int userId) {
    856             // This code will touch the remote print spooler which
    857             // must be called off the main thread, so post the work.
    858             BackgroundThread.getHandler().post(new Runnable() {
    859                 @Override
    860                 public void run() {
    861                     synchronized (mLock) {
    862                         UserState userState = mUserStates.get(userId);
    863                         if (userState != null) {
    864                             userState.destroyLocked();
    865                             mUserStates.remove(userId);
    866                         }
    867                     }
    868                 }
    869             });
    870         }
    871 
    872         private int resolveCallingProfileParentLocked(int userId) {
    873             if (userId != getCurrentUserId()) {
    874                 final long identity = Binder.clearCallingIdentity();
    875                 try {
    876                     UserInfo parent = mUserManager.getProfileParent(userId);
    877                     if (parent != null) {
    878                         return parent.getUserHandle().getIdentifier();
    879                     } else {
    880                         return BACKGROUND_USER_ID;
    881                     }
    882                 } finally {
    883                     Binder.restoreCallingIdentity(identity);
    884                 }
    885             }
    886             return userId;
    887         }
    888 
    889         private int resolveCallingAppEnforcingPermissions(int appId) {
    890             final int callingUid = Binder.getCallingUid();
    891             if (callingUid == 0 || callingUid == Process.SYSTEM_UID
    892                     || callingUid == Process.SHELL_UID) {
    893                 return appId;
    894             }
    895             final int callingAppId = UserHandle.getAppId(callingUid);
    896             if (appId == callingAppId) {
    897                 return appId;
    898             }
    899             if (mContext.checkCallingPermission(
    900                     "com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS")
    901                     != PackageManager.PERMISSION_GRANTED) {
    902                 throw new SecurityException("Call from app " + callingAppId + " as app "
    903                         + appId + " without com.android.printspooler.permission"
    904                         + ".ACCESS_ALL_PRINT_JOBS");
    905             }
    906             return appId;
    907         }
    908 
    909         private int resolveCallingUserEnforcingPermissions(int userId) {
    910             try {
    911                 return ActivityManager.getService().handleIncomingUser(Binder.getCallingPid(),
    912                         Binder.getCallingUid(), userId, true, true, "", null);
    913             } catch (RemoteException re) {
    914                 // Shouldn't happen, local.
    915             }
    916             return userId;
    917         }
    918 
    919         private @NonNull String resolveCallingPackageNameEnforcingSecurity(
    920                 @NonNull String packageName) {
    921             String[] packages = mContext.getPackageManager().getPackagesForUid(
    922                     Binder.getCallingUid());
    923             final int packageCount = packages.length;
    924             for (int i = 0; i < packageCount; i++) {
    925                 if (packageName.equals(packages[i])) {
    926                     return packageName;
    927                 }
    928             }
    929             throw new IllegalArgumentException("packageName has to belong to the caller");
    930         }
    931 
    932         private int getCurrentUserId () {
    933             final long identity = Binder.clearCallingIdentity();
    934             try {
    935                 return ActivityManager.getCurrentUser();
    936             } finally {
    937                 Binder.restoreCallingIdentity(identity);
    938             }
    939         }
    940     }
    941 }
    942