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 android.Manifest;
20import android.app.ActivityManager;
21import android.app.ActivityManagerNative;
22import android.app.Notification;
23import android.app.NotificationManager;
24import android.app.PendingIntent;
25import android.content.ComponentName;
26import android.content.Context;
27import android.content.Intent;
28import android.content.pm.PackageManager;
29import android.content.pm.PackageManager.NameNotFoundException;
30import android.content.pm.ResolveInfo;
31import android.content.pm.ServiceInfo;
32import android.content.pm.UserInfo;
33import android.database.ContentObserver;
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.print.IPrinterDiscoveryObserver;
45import android.print.PrintAttributes;
46import android.print.PrintJobId;
47import android.print.PrintJobInfo;
48import android.print.PrinterId;
49import android.printservice.PrintServiceInfo;
50import android.provider.Settings;
51import android.text.TextUtils;
52import android.util.SparseArray;
53
54import com.android.internal.R;
55import com.android.internal.content.PackageMonitor;
56import com.android.internal.os.BackgroundThread;
57import com.android.server.SystemService;
58
59import java.io.FileDescriptor;
60import java.io.PrintWriter;
61import java.util.Iterator;
62import java.util.List;
63import java.util.Set;
64
65/**
66 * SystemService wrapper for the PrintManager implementation. Publishes
67 * Context.PRINT_SERVICE.
68 * PrintManager implementation is contained within.
69 */
70
71public final class PrintManagerService extends SystemService {
72    private final PrintManagerImpl mPrintManagerImpl;
73
74    public PrintManagerService(Context context) {
75        super(context);
76        mPrintManagerImpl = new PrintManagerImpl(context);
77    }
78
79    @Override
80    public void onStart() {
81        publishBinderService(Context.PRINT_SERVICE, mPrintManagerImpl);
82    }
83
84    @Override
85    public void onStartUser(int userHandle) {
86        mPrintManagerImpl.handleUserStarted(userHandle);
87    }
88
89    @Override
90    public void onStopUser(int userHandle) {
91        mPrintManagerImpl.handleUserStopped(userHandle);
92    }
93
94    class PrintManagerImpl extends IPrintManager.Stub {
95        private static final char COMPONENT_NAME_SEPARATOR = ':';
96
97        private static final String EXTRA_PRINT_SERVICE_COMPONENT_NAME =
98                "EXTRA_PRINT_SERVICE_COMPONENT_NAME";
99
100        private static final int BACKGROUND_USER_ID = -10;
101
102        private final Object mLock = new Object();
103
104        private final Context mContext;
105
106        private final UserManager mUserManager;
107
108        private final SparseArray<UserState> mUserStates = new SparseArray<>();
109
110        PrintManagerImpl(Context context) {
111            mContext = context;
112            mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
113            registerContentObservers();
114            registerBroadcastReceivers();
115        }
116
117        @Override
118        public Bundle print(String printJobName, IPrintDocumentAdapter adapter,
119                PrintAttributes attributes, String packageName, int appId, int userId) {
120            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
121            final int resolvedAppId;
122            final UserState userState;
123            final String resolvedPackageName;
124            synchronized (mLock) {
125                // Only the current group members can start new print jobs.
126                if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
127                    return null;
128                }
129                resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
130                resolvedPackageName = resolveCallingPackageNameEnforcingSecurity(packageName);
131                userState = getOrCreateUserStateLocked(resolvedUserId);
132            }
133            final long identity = Binder.clearCallingIdentity();
134            try {
135                return userState.print(printJobName, adapter, attributes,
136                        resolvedPackageName, resolvedAppId);
137            } finally {
138                Binder.restoreCallingIdentity(identity);
139            }
140        }
141
142        @Override
143        public List<PrintJobInfo> getPrintJobInfos(int appId, int userId) {
144            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
145            final int resolvedAppId;
146            final UserState userState;
147            synchronized (mLock) {
148                // Only the current group members can query for state of print jobs.
149                if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
150                    return null;
151                }
152                resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
153                userState = getOrCreateUserStateLocked(resolvedUserId);
154            }
155            final long identity = Binder.clearCallingIdentity();
156            try {
157                return userState.getPrintJobInfos(resolvedAppId);
158            } finally {
159                Binder.restoreCallingIdentity(identity);
160            }
161        }
162
163        @Override
164        public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId, int userId) {
165            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
166            final int resolvedAppId;
167            final UserState userState;
168            synchronized (mLock) {
169                // Only the current group members can query for state of a print job.
170                if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
171                    return null;
172                }
173                resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
174                userState = getOrCreateUserStateLocked(resolvedUserId);
175            }
176            final long identity = Binder.clearCallingIdentity();
177            try {
178                return userState.getPrintJobInfo(printJobId, resolvedAppId);
179            } finally {
180                Binder.restoreCallingIdentity(identity);
181            }
182        }
183
184        @Override
185        public void cancelPrintJob(PrintJobId printJobId, int appId, int userId) {
186            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
187            final int resolvedAppId;
188            final UserState userState;
189            synchronized (mLock) {
190                // Only the current group members can cancel a print job.
191                if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
192                    return;
193                }
194                resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
195                userState = getOrCreateUserStateLocked(resolvedUserId);
196            }
197            final long identity = Binder.clearCallingIdentity();
198            try {
199                userState.cancelPrintJob(printJobId, resolvedAppId);
200            } finally {
201                Binder.restoreCallingIdentity(identity);
202            }
203        }
204
205        @Override
206        public void restartPrintJob(PrintJobId printJobId, int appId, int userId) {
207            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
208            final int resolvedAppId;
209            final UserState userState;
210            synchronized (mLock) {
211                // Only the current group members can restart a print job.
212                if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
213                    return;
214                }
215                resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
216                userState = getOrCreateUserStateLocked(resolvedUserId);
217            }
218            final long identity = Binder.clearCallingIdentity();
219            try {
220                userState.restartPrintJob(printJobId, resolvedAppId);
221            } finally {
222                Binder.restoreCallingIdentity(identity);
223            }
224        }
225
226        @Override
227        public List<PrintServiceInfo> getEnabledPrintServices(int userId) {
228            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
229            final UserState userState;
230            synchronized (mLock) {
231                // Only the current group members can get enabled services.
232                if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
233                    return null;
234                }
235                userState = getOrCreateUserStateLocked(resolvedUserId);
236            }
237            final long identity = Binder.clearCallingIdentity();
238            try {
239                return userState.getEnabledPrintServices();
240            } finally {
241                Binder.restoreCallingIdentity(identity);
242            }
243        }
244
245        @Override
246        public List<PrintServiceInfo> getInstalledPrintServices(int userId) {
247            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
248            final UserState userState;
249            synchronized (mLock) {
250                // Only the current group members can get installed services.
251                if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
252                    return null;
253                }
254                userState = getOrCreateUserStateLocked(resolvedUserId);
255            }
256            final long identity = Binder.clearCallingIdentity();
257            try {
258                return userState.getInstalledPrintServices();
259            } finally {
260                Binder.restoreCallingIdentity(identity);
261            }
262        }
263
264        @Override
265        public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
266                int userId) {
267            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
268            final UserState userState;
269            synchronized (mLock) {
270                // Only the current group members can create a discovery session.
271                if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
272                    return;
273                }
274                userState = getOrCreateUserStateLocked(resolvedUserId);
275            }
276            final long identity = Binder.clearCallingIdentity();
277            try {
278                userState.createPrinterDiscoverySession(observer);
279            } finally {
280                Binder.restoreCallingIdentity(identity);
281            }
282        }
283
284        @Override
285        public void destroyPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
286                int userId) {
287            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
288            final UserState userState;
289            synchronized (mLock) {
290                // Only the current group members can destroy a discovery session.
291                if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
292                    return;
293                }
294                userState = getOrCreateUserStateLocked(resolvedUserId);
295            }
296            final long identity = Binder.clearCallingIdentity();
297            try {
298                userState.destroyPrinterDiscoverySession(observer);
299            } finally {
300                Binder.restoreCallingIdentity(identity);
301            }
302        }
303
304        @Override
305        public void startPrinterDiscovery(IPrinterDiscoveryObserver observer,
306                List<PrinterId> priorityList, int userId) {
307            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
308            final UserState userState;
309            synchronized (mLock) {
310                // Only the current group members can start discovery.
311                if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
312                    return;
313                }
314                userState = getOrCreateUserStateLocked(resolvedUserId);
315            }
316            final long identity = Binder.clearCallingIdentity();
317            try {
318                userState.startPrinterDiscovery(observer, priorityList);
319            } finally {
320                Binder.restoreCallingIdentity(identity);
321            }
322        }
323
324        @Override
325        public void stopPrinterDiscovery(IPrinterDiscoveryObserver observer, int userId) {
326            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
327            final UserState userState;
328            synchronized (mLock) {
329                // Only the current group members can stop discovery.
330                if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
331                    return;
332                }
333                userState = getOrCreateUserStateLocked(resolvedUserId);
334            }
335            final long identity = Binder.clearCallingIdentity();
336            try {
337                userState.stopPrinterDiscovery(observer);
338            } finally {
339                Binder.restoreCallingIdentity(identity);
340            }
341        }
342
343        @Override
344        public void validatePrinters(List<PrinterId> printerIds, int userId) {
345            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
346            final UserState userState;
347            synchronized (mLock) {
348                // Only the current group members can validate printers.
349                if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
350                    return;
351                }
352                userState = getOrCreateUserStateLocked(resolvedUserId);
353            }
354            final long identity = Binder.clearCallingIdentity();
355            try {
356                userState.validatePrinters(printerIds);
357            } finally {
358                Binder.restoreCallingIdentity(identity);
359            }
360        }
361
362        @Override
363        public void startPrinterStateTracking(PrinterId printerId, int userId) {
364            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
365            final UserState userState;
366            synchronized (mLock) {
367                // Only the current group members can start printer tracking.
368                if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
369                    return;
370                }
371                userState = getOrCreateUserStateLocked(resolvedUserId);
372            }
373            final long identity = Binder.clearCallingIdentity();
374            try {
375                userState.startPrinterStateTracking(printerId);
376            } finally {
377                Binder.restoreCallingIdentity(identity);
378            }
379        }
380
381        @Override
382        public void stopPrinterStateTracking(PrinterId printerId, int userId) {
383            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
384            final UserState userState;
385            synchronized (mLock) {
386                // Only the current group members can stop printer tracking.
387                if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
388                    return;
389                }
390                userState = getOrCreateUserStateLocked(resolvedUserId);
391            }
392            final long identity = Binder.clearCallingIdentity();
393            try {
394                userState.stopPrinterStateTracking(printerId);
395            } finally {
396                Binder.restoreCallingIdentity(identity);
397            }
398        }
399
400        @Override
401        public void addPrintJobStateChangeListener(IPrintJobStateChangeListener listener,
402                int appId, int userId) throws RemoteException {
403            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
404            final int resolvedAppId;
405            final UserState userState;
406            synchronized (mLock) {
407                // Only the current group members can add a print job listener.
408                if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
409                    return;
410                }
411                resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
412                userState = getOrCreateUserStateLocked(resolvedUserId);
413            }
414            final long identity = Binder.clearCallingIdentity();
415            try {
416                userState.addPrintJobStateChangeListener(listener, resolvedAppId);
417            } finally {
418                Binder.restoreCallingIdentity(identity);
419            }
420        }
421
422        @Override
423        public void removePrintJobStateChangeListener(IPrintJobStateChangeListener listener,
424                int userId) {
425            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
426            final UserState userState;
427            synchronized (mLock) {
428                // Only the current group members can remove a print job listener.
429                if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
430                    return;
431                }
432                userState = getOrCreateUserStateLocked(resolvedUserId);
433            }
434            final long identity = Binder.clearCallingIdentity();
435            try {
436                userState.removePrintJobStateChangeListener(listener);
437            } finally {
438                Binder.restoreCallingIdentity(identity);
439            }
440        }
441
442        @Override
443        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
444            if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
445                    != PackageManager.PERMISSION_GRANTED) {
446                pw.println("Permission Denial: can't dump PrintManager from from pid="
447                        + Binder.getCallingPid()
448                        + ", uid=" + Binder.getCallingUid());
449                return;
450            }
451
452            synchronized (mLock) {
453                final long identity = Binder.clearCallingIdentity();
454                try {
455                    pw.println("PRINT MANAGER STATE (dumpsys print)");
456                    final int userStateCount = mUserStates.size();
457                    for (int i = 0; i < userStateCount; i++) {
458                        UserState userState = mUserStates.valueAt(i);
459                        userState.dump(fd, pw, "");
460                        pw.println();
461                    }
462                } finally {
463                    Binder.restoreCallingIdentity(identity);
464                }
465            }
466        }
467
468        private void registerContentObservers() {
469            final Uri enabledPrintServicesUri = Settings.Secure.getUriFor(
470                    Settings.Secure.ENABLED_PRINT_SERVICES);
471            ContentObserver observer = new ContentObserver(BackgroundThread.getHandler()) {
472                @Override
473                public void onChange(boolean selfChange, Uri uri, int userId) {
474                    if (enabledPrintServicesUri.equals(uri)) {
475                        synchronized (mLock) {
476                            if (userId != UserHandle.USER_ALL) {
477                                UserState userState = getOrCreateUserStateLocked(userId);
478                                userState.updateIfNeededLocked();
479                            } else {
480                                final int userCount = mUserStates.size();
481                                for (int i = 0; i < userCount; i++) {
482                                    UserState userState = mUserStates.valueAt(i);
483                                    userState.updateIfNeededLocked();
484                                }
485                            }
486                        }
487                    }
488                }
489            };
490
491            mContext.getContentResolver().registerContentObserver(enabledPrintServicesUri,
492                    false, observer, UserHandle.USER_ALL);
493        }
494
495        private void registerBroadcastReceivers() {
496            PackageMonitor monitor = new PackageMonitor() {
497                @Override
498                public void onPackageModified(String packageName) {
499                    synchronized (mLock) {
500                        // A background user/profile's print jobs are running but there is
501                        // no UI shown. Hence, if the packages of such a user change we need
502                        // to handle it as the change may affect ongoing print jobs.
503                        boolean servicesChanged = false;
504                        UserState userState = getOrCreateUserStateLocked(getChangingUserId());
505                        Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
506                        while (iterator.hasNext()) {
507                            ComponentName componentName = iterator.next();
508                            if (packageName.equals(componentName.getPackageName())) {
509                                servicesChanged = true;
510                            }
511                        }
512                        if (servicesChanged) {
513                            userState.updateIfNeededLocked();
514                        }
515                    }
516                }
517
518                @Override
519                public void onPackageRemoved(String packageName, int uid) {
520                    synchronized (mLock) {
521                        // A background user/profile's print jobs are running but there is
522                        // no UI shown. Hence, if the packages of such a user change we need
523                        // to handle it as the change may affect ongoing print jobs.
524                        boolean servicesRemoved = false;
525                        UserState userState = getOrCreateUserStateLocked(getChangingUserId());
526                        Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
527                        while (iterator.hasNext()) {
528                            ComponentName componentName = iterator.next();
529                            if (packageName.equals(componentName.getPackageName())) {
530                                iterator.remove();
531                                servicesRemoved = true;
532                            }
533                        }
534                        if (servicesRemoved) {
535                            persistComponentNamesToSettingLocked(
536                                    Settings.Secure.ENABLED_PRINT_SERVICES,
537                                    userState.getEnabledServices(), getChangingUserId());
538                            userState.updateIfNeededLocked();
539                        }
540                    }
541                }
542
543                @Override
544                public boolean onHandleForceStop(Intent intent, String[] stoppedPackages,
545                        int uid, boolean doit) {
546                    synchronized (mLock) {
547                        // A background user/profile's print jobs are running but there is
548                        // no UI shown. Hence, if the packages of such a user change we need
549                        // to handle it as the change may affect ongoing print jobs.
550                        UserState userState = getOrCreateUserStateLocked(getChangingUserId());
551                        boolean stoppedSomePackages = false;
552                        Iterator<ComponentName> iterator = userState.getEnabledServices()
553                                .iterator();
554                        while (iterator.hasNext()) {
555                            ComponentName componentName = iterator.next();
556                            String componentPackage = componentName.getPackageName();
557                            for (String stoppedPackage : stoppedPackages) {
558                                if (componentPackage.equals(stoppedPackage)) {
559                                    if (!doit) {
560                                        return true;
561                                    }
562                                    stoppedSomePackages = true;
563                                    break;
564                                }
565                            }
566                        }
567                        if (stoppedSomePackages) {
568                            userState.updateIfNeededLocked();
569                        }
570                        return false;
571                    }
572                }
573
574                @Override
575                public void onPackageAdded(String packageName, int uid) {
576                    // A background user/profile's print jobs are running but there is
577                    // no UI shown. Hence, if the packages of such a user change we need
578                    // to handle it as the change may affect ongoing print jobs.
579                    Intent intent = new Intent(android.printservice.PrintService.SERVICE_INTERFACE);
580                    intent.setPackage(packageName);
581
582                    List<ResolveInfo> installedServices = mContext.getPackageManager()
583                            .queryIntentServicesAsUser(intent, PackageManager.GET_SERVICES,
584                                    getChangingUserId());
585
586                    if (installedServices == null) {
587                        return;
588                    }
589
590                    final int installedServiceCount = installedServices.size();
591                    for (int i = 0; i < installedServiceCount; i++) {
592                        ServiceInfo serviceInfo = installedServices.get(i).serviceInfo;
593                        ComponentName component = new ComponentName(serviceInfo.packageName,
594                                serviceInfo.name);
595                        String label = serviceInfo.loadLabel(mContext.getPackageManager())
596                                .toString();
597                        showEnableInstalledPrintServiceNotification(component, label,
598                                getChangingUserId());
599                    }
600                }
601
602                private void persistComponentNamesToSettingLocked(String settingName,
603                        Set<ComponentName> componentNames, int userId) {
604                    StringBuilder builder = new StringBuilder();
605                    for (ComponentName componentName : componentNames) {
606                        if (builder.length() > 0) {
607                            builder.append(COMPONENT_NAME_SEPARATOR);
608                        }
609                        builder.append(componentName.flattenToShortString());
610                    }
611                    Settings.Secure.putStringForUser(mContext.getContentResolver(),
612                            settingName, builder.toString(), userId);
613                }
614            };
615
616            // package changes
617            monitor.register(mContext, BackgroundThread.getHandler().getLooper(),
618                    UserHandle.ALL, true);
619        }
620
621        private UserState getOrCreateUserStateLocked(int userId) {
622            UserState userState = mUserStates.get(userId);
623            if (userState == null) {
624                userState = new UserState(mContext, userId, mLock);
625                mUserStates.put(userId, userState);
626            }
627            return userState;
628        }
629
630        private void handleUserStarted(final int userId) {
631            // This code will touch the remote print spooler which
632            // must be called off the main thread, so post the work.
633            BackgroundThread.getHandler().post(new Runnable() {
634                @Override
635                public void run() {
636                    UserState userState;
637                    synchronized (mLock) {
638                        userState = getOrCreateUserStateLocked(userId);
639                        userState.updateIfNeededLocked();
640                    }
641                    // This is the first time we switch to this user after boot, so
642                    // now is the time to remove obsolete print jobs since they
643                    // are from the last boot and no application would query them.
644                    userState.removeObsoletePrintJobs();
645                }
646            });
647        }
648
649        private void handleUserStopped(final int userId) {
650            // This code will touch the remote print spooler which
651            // must be called off the main thread, so post the work.
652            BackgroundThread.getHandler().post(new Runnable() {
653                @Override
654                public void run() {
655                    synchronized (mLock) {
656                        UserState userState = mUserStates.get(userId);
657                        if (userState != null) {
658                            userState.destroyLocked();
659                            mUserStates.remove(userId);
660                        }
661                    }
662                }
663            });
664        }
665
666        private int resolveCallingProfileParentLocked(int userId) {
667            if (userId != getCurrentUserId()) {
668                final long identity = Binder.clearCallingIdentity();
669                try {
670                    UserInfo parent = mUserManager.getProfileParent(userId);
671                    if (parent != null) {
672                        return parent.getUserHandle().getIdentifier();
673                    } else {
674                        return BACKGROUND_USER_ID;
675                    }
676                } finally {
677                    Binder.restoreCallingIdentity(identity);
678                }
679            }
680            return userId;
681        }
682
683        private int resolveCallingAppEnforcingPermissions(int appId) {
684            final int callingUid = Binder.getCallingUid();
685            if (callingUid == 0 || callingUid == Process.SYSTEM_UID
686                    || callingUid == Process.SHELL_UID) {
687                return appId;
688            }
689            final int callingAppId = UserHandle.getAppId(callingUid);
690            if (appId == callingAppId) {
691                return appId;
692            }
693            if (mContext.checkCallingPermission(
694                    "com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS")
695                    != PackageManager.PERMISSION_GRANTED) {
696                throw new SecurityException("Call from app " + callingAppId + " as app "
697                        + appId + " without com.android.printspooler.permission"
698                        + ".ACCESS_ALL_PRINT_JOBS");
699            }
700            return appId;
701        }
702
703        private int resolveCallingUserEnforcingPermissions(int userId) {
704            try {
705                return ActivityManagerNative.getDefault().handleIncomingUser(Binder.getCallingPid(),
706                        Binder.getCallingUid(), userId, true, true, "", null);
707            } catch (RemoteException re) {
708                // Shouldn't happen, local.
709            }
710            return userId;
711        }
712
713        private String resolveCallingPackageNameEnforcingSecurity(String packageName) {
714            if (TextUtils.isEmpty(packageName)) {
715                return null;
716            }
717            String[] packages = mContext.getPackageManager().getPackagesForUid(
718                    Binder.getCallingUid());
719            final int packageCount = packages.length;
720            for (int i = 0; i < packageCount; i++) {
721                if (packageName.equals(packages[i])) {
722                    return packageName;
723                }
724            }
725            return null;
726        }
727
728        private int getCurrentUserId () {
729            final long identity = Binder.clearCallingIdentity();
730            try {
731                return ActivityManager.getCurrentUser();
732            } finally {
733                Binder.restoreCallingIdentity(identity);
734            }
735        }
736
737        private void showEnableInstalledPrintServiceNotification(ComponentName component,
738                String label, int userId) {
739            UserHandle userHandle = new UserHandle(userId);
740
741            Intent intent = new Intent(Settings.ACTION_PRINT_SETTINGS);
742            intent.putExtra(EXTRA_PRINT_SERVICE_COMPONENT_NAME, component.flattenToString());
743
744            PendingIntent pendingIntent = PendingIntent.getActivityAsUser(mContext, 0, intent,
745                    PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT, null,
746                    userHandle);
747
748            Context builderContext = mContext;
749            try {
750                builderContext = mContext.createPackageContextAsUser(mContext.getPackageName(), 0,
751                        userHandle);
752            } catch (NameNotFoundException e) {
753                // Ignore can't find the package the system is running as.
754            }
755            Notification.Builder builder = new Notification.Builder(builderContext)
756                    .setSmallIcon(R.drawable.ic_print)
757                    .setContentTitle(mContext.getString(R.string.print_service_installed_title,
758                            label))
759                    .setContentText(mContext.getString(R.string.print_service_installed_message))
760                    .setContentIntent(pendingIntent)
761                    .setWhen(System.currentTimeMillis())
762                    .setAutoCancel(true)
763                    .setShowWhen(true)
764                    .setColor(mContext.getResources().getColor(
765                            com.android.internal.R.color.system_notification_accent_color));
766
767            NotificationManager notificationManager = (NotificationManager) mContext
768                    .getSystemService(Context.NOTIFICATION_SERVICE);
769
770            String notificationTag = getClass().getName() + ":" + component.flattenToString();
771            notificationManager.notifyAsUser(notificationTag, 0, builder.build(),
772                    userHandle);
773        }
774    }
775}
776