blob: 86e76852b4d5d042c1c4e8b36ee9d13d7086f318 [file] [log] [blame]
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -07001/*
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.content.BroadcastReceiver;
21import android.content.ComponentName;
22import android.content.Context;
23import android.content.Intent;
24import android.content.IntentFilter;
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070025import android.content.pm.PackageManager;
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070026import android.database.ContentObserver;
27import android.net.Uri;
28import android.os.Binder;
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070029import android.os.Process;
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070030import android.os.UserHandle;
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070031import android.print.IPrintClient;
Svetoslav Ganova0027152013-06-25 14:59:53 -070032import android.print.IPrintDocumentAdapter;
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070033import android.print.IPrintManager;
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070034import android.print.PrintAttributes;
35import android.print.PrintJobInfo;
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070036import android.provider.Settings;
Svetoslav Ganova0027152013-06-25 14:59:53 -070037import android.util.SparseArray;
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070038
39import com.android.internal.content.PackageMonitor;
Svetoslav Ganova0027152013-06-25 14:59:53 -070040import com.android.internal.os.BackgroundThread;
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070041
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070042import java.util.Iterator;
43import java.util.List;
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070044import java.util.Set;
45
46public final class PrintManagerService extends IPrintManager.Stub {
47
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070048 private static final char COMPONENT_NAME_SEPARATOR = ':';
49
50 private final Object mLock = new Object();
51
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070052 private final Context mContext;
53
Svetoslav Ganova0027152013-06-25 14:59:53 -070054 private final SparseArray<UserState> mUserStates = new SparseArray<UserState>();
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070055
56 private int mCurrentUserId = UserHandle.USER_OWNER;
57
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070058 public PrintManagerService(Context context) {
59 mContext = context;
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070060 registerContentObservers();
Svetoslav Ganova0027152013-06-25 14:59:53 -070061 registerBoradcastReceivers();
62 }
63
64 public void systemRuning() {
65 BackgroundThread.getHandler().post(new Runnable() {
66 @Override
67 public void run() {
68 synchronized (mLock) {
69 UserState userState = getCurrentUserStateLocked();
70 userState.updateIfNeededLocked();
71 userState.getSpoolerLocked().notifyClientForActivteJobs();
72 }
73 }
74 });
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070075 }
76
77 @Override
Svetoslav Ganova0027152013-06-25 14:59:53 -070078 public PrintJobInfo print(String printJobName, IPrintClient client,
79 IPrintDocumentAdapter documentAdapter, PrintAttributes attributes, int appId,
80 int userId) {
81 final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
82 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
83 final UserState userState;
84 final RemotePrintSpooler spooler;
85 synchronized (mLock) {
86 userState = getOrCreateUserStateLocked(resolvedUserId);
87 spooler = userState.getSpoolerLocked();
88 }
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070089 final long identity = Binder.clearCallingIdentity();
90 try {
Svetoslav Ganova0027152013-06-25 14:59:53 -070091 return spooler.createPrintJob(printJobName, client, documentAdapter,
92 attributes, resolvedAppId);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -070093 } finally {
94 Binder.restoreCallingIdentity(identity);
95 }
96 }
97
98 @Override
Svetoslav Ganova0027152013-06-25 14:59:53 -070099 public List<PrintJobInfo> getPrintJobInfos(int appId, int userId) {
100 final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
101 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
102 final UserState userState;
103 final RemotePrintSpooler spooler;
104 synchronized (mLock) {
105 userState = getOrCreateUserStateLocked(resolvedUserId);
106 spooler = userState.getSpoolerLocked();
107 }
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700108 final long identity = Binder.clearCallingIdentity();
109 try {
Svetoslav Ganova0027152013-06-25 14:59:53 -0700110 return spooler.getPrintJobInfos(null, PrintJobInfo.STATE_ANY,
111 resolvedAppId);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700112 } finally {
113 Binder.restoreCallingIdentity(identity);
114 }
115 }
116
117 @Override
Svetoslav Ganova0027152013-06-25 14:59:53 -0700118 public PrintJobInfo getPrintJobInfo(int printJobId, int appId, int userId) {
119 final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
120 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
121 final UserState userState;
122 final RemotePrintSpooler spooler;
123 synchronized (mLock) {
124 userState = getOrCreateUserStateLocked(resolvedUserId);
125 spooler = userState.getSpoolerLocked();
126 }
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700127 final long identity = Binder.clearCallingIdentity();
128 try {
Svetoslav Ganova0027152013-06-25 14:59:53 -0700129 return spooler.getPrintJobInfo(printJobId, resolvedAppId);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700130 } finally {
131 Binder.restoreCallingIdentity(identity);
132 }
133 }
134
135 @Override
136 public void cancelPrintJob(int printJobId, int appId, int userId) {
Svetoslav Ganova0027152013-06-25 14:59:53 -0700137 final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
138 final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
139 final UserState userState;
140 final RemotePrintSpooler spooler;
141 synchronized (mLock) {
142 userState = getOrCreateUserStateLocked(resolvedUserId);
143 spooler = userState.getSpoolerLocked();
144 }
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700145 final long identity = Binder.clearCallingIdentity();
146 try {
Svetoslav Ganova0027152013-06-25 14:59:53 -0700147 if (spooler.cancelPrintJob(printJobId, resolvedAppId)) {
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700148 return;
149 }
Svetoslav Ganova0027152013-06-25 14:59:53 -0700150 PrintJobInfo printJobInfo = getPrintJobInfo(printJobId, resolvedAppId, resolvedUserId);
151 if (printJobInfo == null) {
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700152 return;
153 }
Svetoslav Ganova0027152013-06-25 14:59:53 -0700154 ComponentName printServiceName = printJobInfo.getPrinterId().getService();
155 RemotePrintService printService = null;
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700156 synchronized (mLock) {
Svetoslav Ganova0027152013-06-25 14:59:53 -0700157 printService = userState.getActiveServices().get(printServiceName);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700158 }
159 if (printService == null) {
160 return;
161 }
Svetoslav Ganova0027152013-06-25 14:59:53 -0700162 printService.onRequestCancelPrintJob(printJobInfo);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700163 } finally {
164 Binder.restoreCallingIdentity(identity);
165 }
166 }
167
168 private void registerContentObservers() {
169 final Uri enabledPrintServicesUri = Settings.Secure.getUriFor(
170 Settings.Secure.ENABLED_PRINT_SERVICES);
171
Svetoslav Ganova0027152013-06-25 14:59:53 -0700172 ContentObserver observer = new ContentObserver(BackgroundThread.getHandler()) {
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700173 @Override
174 public void onChange(boolean selfChange, Uri uri) {
175 if (enabledPrintServicesUri.equals(uri)) {
176 synchronized (mLock) {
Svetoslav Ganova0027152013-06-25 14:59:53 -0700177 UserState userState = getCurrentUserStateLocked();
178 userState.updateIfNeededLocked();
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700179 }
180 }
181 }
182 };
183
184 mContext.getContentResolver().registerContentObserver(enabledPrintServicesUri,
185 false, observer, UserHandle.USER_ALL);
186 }
187
Svetoslav Ganova0027152013-06-25 14:59:53 -0700188 private void registerBoradcastReceivers() {
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700189 PackageMonitor monitor = new PackageMonitor() {
190 @Override
Svetoslav Ganova0027152013-06-25 14:59:53 -0700191 public boolean onPackageChanged(String packageName, int uid, String[] components) {
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700192 synchronized (mLock) {
Svetoslav Ganova0027152013-06-25 14:59:53 -0700193 UserState userState = getOrCreateUserStateLocked(getChangingUserId());
194 Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
195 while (iterator.hasNext()) {
196 ComponentName componentName = iterator.next();
197 if (packageName.equals(componentName.getPackageName())) {
198 userState.updateIfNeededLocked();
199 return true;
200 }
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700201 }
202 }
Svetoslav Ganova0027152013-06-25 14:59:53 -0700203 return false;
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700204 }
205
206 @Override
207 public void onPackageRemoved(String packageName, int uid) {
208 synchronized (mLock) {
Svetoslav Ganova0027152013-06-25 14:59:53 -0700209 UserState userState = getOrCreateUserStateLocked(getChangingUserId());
210 Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700211 while (iterator.hasNext()) {
212 ComponentName componentName = iterator.next();
213 if (packageName.equals(componentName.getPackageName())) {
214 iterator.remove();
Svetoslav Ganova0027152013-06-25 14:59:53 -0700215 persistComponentNamesToSettingLocked(
216 Settings.Secure.ENABLED_PRINT_SERVICES,
217 userState.getEnabledServices(), getChangingUserId());
218 userState.updateIfNeededLocked();
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700219 return;
220 }
221 }
222 }
223 }
224
225 @Override
226 public boolean onHandleForceStop(Intent intent, String[] stoppedPackages,
227 int uid, boolean doit) {
228 synchronized (mLock) {
Svetoslav Ganova0027152013-06-25 14:59:53 -0700229 UserState userState = getOrCreateUserStateLocked(getChangingUserId());
230 boolean stoppedSomePackages = false;
231 Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700232 while (iterator.hasNext()) {
233 ComponentName componentName = iterator.next();
234 String componentPackage = componentName.getPackageName();
235 for (String stoppedPackage : stoppedPackages) {
236 if (componentPackage.equals(stoppedPackage)) {
237 if (!doit) {
238 return true;
239 }
Svetoslav Ganova0027152013-06-25 14:59:53 -0700240 stoppedSomePackages = true;
241 break;
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700242 }
243 }
244 }
Svetoslav Ganova0027152013-06-25 14:59:53 -0700245 if (stoppedSomePackages) {
246 userState.updateIfNeededLocked();
247 }
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700248 return false;
249 }
250 }
251
Svetoslav Ganova0027152013-06-25 14:59:53 -0700252 private void persistComponentNamesToSettingLocked(String settingName,
253 Set<ComponentName> componentNames, int userId) {
254 StringBuilder builder = new StringBuilder();
255 for (ComponentName componentName : componentNames) {
256 if (builder.length() > 0) {
257 builder.append(COMPONENT_NAME_SEPARATOR);
258 }
259 builder.append(componentName.flattenToShortString());
260 }
261 Settings.Secure.putStringForUser(mContext.getContentResolver(),
262 settingName, builder.toString(), userId);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700263 }
264 };
265
266 // package changes
Svetoslav Ganova0027152013-06-25 14:59:53 -0700267 monitor.register(mContext, BackgroundThread.getHandler().getLooper(),
268 UserHandle.ALL, true);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700269
270 // user changes
271 IntentFilter intentFilter = new IntentFilter();
272 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
273
274 mContext.registerReceiverAsUser(new BroadcastReceiver() {
275 @Override
276 public void onReceive(Context context, Intent intent) {
277 String action = intent.getAction();
278 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
279 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
Svetoslav Ganova0027152013-06-25 14:59:53 -0700280 } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
281 removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700282 }
283 }
Svetoslav Ganova0027152013-06-25 14:59:53 -0700284 }, UserHandle.ALL, intentFilter, null, BackgroundThread.getHandler());
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700285 }
286
Svetoslav Ganova0027152013-06-25 14:59:53 -0700287 private UserState getCurrentUserStateLocked() {
288 return getOrCreateUserStateLocked(mCurrentUserId);
289 }
290
291 private UserState getOrCreateUserStateLocked(int userId) {
292 UserState userState = mUserStates.get(userId);
293 if (userState == null) {
294 userState = new UserState(mContext, userId, mLock);
295 mUserStates.put(userId, userState);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700296 }
Svetoslav Ganova0027152013-06-25 14:59:53 -0700297 return userState;
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700298 }
299
300 private void switchUser(int newUserId) {
301 synchronized (mLock) {
Svetoslav Ganova0027152013-06-25 14:59:53 -0700302 if (newUserId == mCurrentUserId) {
303 return;
304 }
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700305 mCurrentUserId = newUserId;
Svetoslav Ganova0027152013-06-25 14:59:53 -0700306 UserState userState = getCurrentUserStateLocked();
307 userState.updateIfNeededLocked();
308 userState.getSpoolerLocked().notifyClientForActivteJobs();
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700309 }
310 }
311
Svetoslav Ganova0027152013-06-25 14:59:53 -0700312 private void removeUser(int removedUserId) {
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700313 synchronized (mLock) {
Svetoslav Ganova0027152013-06-25 14:59:53 -0700314 UserState userState = mUserStates.get(removedUserId);
315 if (userState != null) {
316 userState.destroyLocked();
317 mUserStates.remove(removedUserId);
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700318 }
319 }
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700320 }
321
Svetoslav Ganova0027152013-06-25 14:59:53 -0700322 private int resolveCallingAppEnforcingPermissions(int appId) {
323 final int callingUid = Binder.getCallingUid();
324 if (callingUid == 0 || callingUid == Process.SYSTEM_UID
325 || callingUid == Process.SHELL_UID) {
326 return appId;
327 }
328 final int callingAppId = UserHandle.getAppId(callingUid);
329 if (appId == callingAppId) {
330 return appId;
331 }
332 if (mContext.checkCallingPermission(Manifest.permission.ACCESS_ALL_PRINT_JOBS)
333 != PackageManager.PERMISSION_GRANTED) {
334 throw new SecurityException("Call from app " + callingAppId + " as app "
335 + appId + " without permission ACCESS_ALL_PRINT_JOBS");
336 }
337 return appId;
338 }
339
340 private int resolveCallingUserEnforcingPermissions(int userId) {
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700341 final int callingUid = Binder.getCallingUid();
342 if (callingUid == 0 || callingUid == Process.SYSTEM_UID
343 || callingUid == Process.SHELL_UID) {
344 return userId;
345 }
346 final int callingUserId = UserHandle.getUserId(callingUid);
347 if (callingUserId == userId) {
348 return userId;
349 }
350 if (mContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)
351 != PackageManager.PERMISSION_GRANTED
352 || mContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS)
353 != PackageManager.PERMISSION_GRANTED) {
354 if (userId == UserHandle.USER_CURRENT_OR_SELF) {
355 return callingUserId;
356 }
357 throw new SecurityException("Call from user " + callingUserId + " as user "
Svetoslav Ganova0027152013-06-25 14:59:53 -0700358 + userId + " without permission INTERACT_ACROSS_USERS or "
359 + "INTERACT_ACROSS_USERS_FULL not allowed.");
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700360 }
361 if (userId == UserHandle.USER_CURRENT || userId == UserHandle.USER_CURRENT_OR_SELF) {
362 return mCurrentUserId;
363 }
364 throw new IllegalArgumentException("Calling user can be changed to only "
365 + "UserHandle.USER_CURRENT or UserHandle.USER_CURRENT_OR_SELF.");
366 }
Svetoslav Ganov4b9a4d12013-06-11 15:20:06 -0700367}