• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.print;
18 
19 import android.Manifest;
20 import android.app.ActivityManager;
21 import android.app.ActivityManagerNative;
22 import android.app.Notification;
23 import android.app.NotificationManager;
24 import android.app.PendingIntent;
25 import android.content.ComponentName;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.pm.PackageManager;
29 import android.content.pm.PackageManager.NameNotFoundException;
30 import android.content.pm.ResolveInfo;
31 import android.content.pm.ServiceInfo;
32 import android.content.pm.UserInfo;
33 import android.database.ContentObserver;
34 import android.net.Uri;
35 import android.os.Binder;
36 import android.os.Bundle;
37 import android.os.Process;
38 import android.os.RemoteException;
39 import android.os.UserHandle;
40 import android.os.UserManager;
41 import android.print.IPrintDocumentAdapter;
42 import android.print.IPrintJobStateChangeListener;
43 import android.print.IPrintManager;
44 import android.print.IPrinterDiscoveryObserver;
45 import android.print.PrintAttributes;
46 import android.print.PrintJobId;
47 import android.print.PrintJobInfo;
48 import android.print.PrinterId;
49 import android.printservice.PrintServiceInfo;
50 import android.provider.Settings;
51 import android.text.TextUtils;
52 import android.util.SparseArray;
53 
54 import com.android.internal.R;
55 import com.android.internal.content.PackageMonitor;
56 import com.android.internal.os.BackgroundThread;
57 import com.android.server.SystemService;
58 
59 import java.io.FileDescriptor;
60 import java.io.PrintWriter;
61 import java.util.Iterator;
62 import java.util.List;
63 import 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 
71 public final class PrintManagerService extends SystemService {
72     private final PrintManagerImpl mPrintManagerImpl;
73 
PrintManagerService(Context context)74     public PrintManagerService(Context context) {
75         super(context);
76         mPrintManagerImpl = new PrintManagerImpl(context);
77     }
78 
79     @Override
onStart()80     public void onStart() {
81         publishBinderService(Context.PRINT_SERVICE, mPrintManagerImpl);
82     }
83 
84     @Override
onStartUser(int userHandle)85     public void onStartUser(int userHandle) {
86         mPrintManagerImpl.handleUserStarted(userHandle);
87     }
88 
89     @Override
onStopUser(int userHandle)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 
PrintManagerImpl(Context context)110         PrintManagerImpl(Context context) {
111             mContext = context;
112             mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
113             registerContentObservers();
114             registerBroadcastReceivers();
115         }
116 
117         @Override
print(String printJobName, IPrintDocumentAdapter adapter, PrintAttributes attributes, String packageName, int appId, int userId)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
getPrintJobInfos(int appId, int userId)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
getPrintJobInfo(PrintJobId printJobId, int appId, int userId)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
cancelPrintJob(PrintJobId printJobId, int appId, int userId)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
restartPrintJob(PrintJobId printJobId, int appId, int userId)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
getEnabledPrintServices(int userId)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
getInstalledPrintServices(int userId)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
createPrinterDiscoverySession(IPrinterDiscoveryObserver observer, int userId)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
destroyPrinterDiscoverySession(IPrinterDiscoveryObserver observer, int userId)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
startPrinterDiscovery(IPrinterDiscoveryObserver observer, List<PrinterId> priorityList, int userId)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
stopPrinterDiscovery(IPrinterDiscoveryObserver observer, int userId)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
validatePrinters(List<PrinterId> printerIds, int userId)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
startPrinterStateTracking(PrinterId printerId, int userId)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
stopPrinterStateTracking(PrinterId printerId, int userId)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
addPrintJobStateChangeListener(IPrintJobStateChangeListener listener, int appId, int userId)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
removePrintJobStateChangeListener(IPrintJobStateChangeListener listener, int userId)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
dump(FileDescriptor fd, PrintWriter pw, String[] args)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 
registerContentObservers()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 
registerBroadcastReceivers()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 
getOrCreateUserStateLocked(int userId)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 
handleUserStarted(final int userId)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 
handleUserStopped(final int userId)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 
resolveCallingProfileParentLocked(int userId)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 
resolveCallingAppEnforcingPermissions(int appId)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 
resolveCallingUserEnforcingPermissions(int userId)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 
resolveCallingPackageNameEnforcingSecurity(String packageName)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 
getCurrentUserId()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 
showEnableInstalledPrintServiceNotification(ComponentName component, String label, int userId)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