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