[go: nahoru, domu]

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