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