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