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