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