diff options
Diffstat (limited to 'services/java')
3 files changed, 354 insertions, 41 deletions
diff --git a/services/java/com/android/server/print/PrintManagerService.java b/services/java/com/android/server/print/PrintManagerService.java index 671a5dc..2563b58 100644 --- a/services/java/com/android/server/print/PrintManagerService.java +++ b/services/java/com/android/server/print/PrintManagerService.java @@ -254,7 +254,7 @@ public final class PrintManagerService extends IPrintManager.Stub { } @Override - public void requestPrinterUpdate(PrinterId printerId, int userId) { + public void validatePrinters(List<PrinterId> printerIds, int userId) { final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); final UserState userState; synchronized (mLock) { @@ -262,7 +262,37 @@ public final class PrintManagerService extends IPrintManager.Stub { } final long identity = Binder.clearCallingIdentity(); try { - userState.requestPrinterUpdate(printerId); + userState.validatePrinters(printerIds); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void startPrinterStateTracking(PrinterId printerId, int userId) { + final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); + final UserState userState; + synchronized (mLock) { + userState = getOrCreateUserStateLocked(resolvedUserId); + } + final long identity = Binder.clearCallingIdentity(); + try { + userState.startPrinterStateTracking(printerId); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void stopPrinterStateTracking(PrinterId printerId, int userId) { + final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); + final UserState userState; + synchronized (mLock) { + userState = getOrCreateUserStateLocked(resolvedUserId); + } + final long identity = Binder.clearCallingIdentity(); + try { + userState.stopPrinterStateTracking(printerId); } finally { Binder.restoreCallingIdentity(identity); } @@ -432,10 +462,12 @@ public final class PrintManagerService extends IPrintManager.Stub { if (appId == callingAppId) { return appId; } - if (mContext.checkCallingPermission(Manifest.permission.ACCESS_ALL_PRINT_JOBS) + if (mContext.checkCallingPermission( + "com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS") != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Call from app " + callingAppId + " as app " - + appId + " without permission ACCESS_ALL_PRINT_JOBS"); + + appId + " without com.android.printspooler.permission" + + ".ACCESS_ALL_PRINT_JOBS"); } return appId; } diff --git a/services/java/com/android/server/print/RemotePrintService.java b/services/java/com/android/server/print/RemotePrintService.java index 7f4b343..14af9d8 100644 --- a/services/java/com/android/server/print/RemotePrintService.java +++ b/services/java/com/android/server/print/RemotePrintService.java @@ -25,6 +25,7 @@ import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.IBinder.DeathRecipient; +import android.os.AsyncTask; import android.os.Looper; import android.os.Message; import android.os.ParcelFileDescriptor; @@ -38,6 +39,8 @@ import android.printservice.IPrintService; import android.printservice.IPrintServiceClient; import android.util.Slog; +import com.android.internal.R; + import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; @@ -121,6 +124,36 @@ final class RemotePrintService implements DeathRecipient { mHasPrinterDiscoverySession = false; mPendingCommands.clear(); ensureUnbound(); + + // Makes sure all active print jobs are failed since the service + // just died. Do this off the main thread since we do to allow + // calls into the spooler on the main thread. + new AsyncTask<Void, Void, Void>() { + @Override + protected Void doInBackground(Void... params) { + failAllActivePrintJobs(); + return null; + } + }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null); + } + + private void failAllActivePrintJobs() { + List<PrintJobInfo> printJobs = mSpooler.getPrintJobInfos(mComponentName, + PrintJobInfo.STATE_ANY_ACTIVE, PrintManager.APP_ID_ANY); + if (printJobs == null) { + return; + } + final long identity = Binder.clearCallingIdentity(); + try { + final int printJobCount = printJobs.size(); + for (int i = 0; i < printJobCount; i++) { + PrintJobInfo printJob = printJobs.get(i); + mSpooler.setPrintJobState(printJob.getId(), PrintJobInfo.STATE_FAILED, + mContext.getString(R.string.reason_unknown)); + } + } finally { + Binder.restoreCallingIdentity(identity); + } } private void handleOnAllPrintJobsHandled() { @@ -308,29 +341,83 @@ final class RemotePrintService implements DeathRecipient { } } - public void requestPrinterUpdate(PrinterId printerId) { - mHandler.obtainMessage(MyHandler.MSG_REQUEST_PRINTER_UPDATE, + public void validatePrinters(List<PrinterId> printerIds) { + mHandler.obtainMessage(MyHandler.MSG_VALIDATE_PRINTERS, + printerIds).sendToTarget(); + } + + private void handleValidatePrinters(final List<PrinterId> printerIds) { + throwIfDestroyed(); + if (!isBound()) { + ensureBound(); + mPendingCommands.add(new Runnable() { + @Override + public void run() { + handleValidatePrinters(printerIds); + } + }); + } else { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserId + "] handleValidatePrinters()"); + } + try { + mPrintService.validatePrinters(printerIds); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error requesting printers validation.", re); + } + } + } + + public void startPrinterStateTracking(PrinterId printerId) { + mHandler.obtainMessage(MyHandler.MSG_START_PRINTER_STATE_TRACKING, + printerId).sendToTarget(); + } + + private void handleStartPrinterStateTracking(final PrinterId printerId) { + throwIfDestroyed(); + if (!isBound()) { + ensureBound(); + mPendingCommands.add(new Runnable() { + @Override + public void run() { + handleStartPrinterStateTracking(printerId); + } + }); + } else { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserId + "] handleStartPrinterTracking()"); + } + try { + mPrintService.startPrinterStateTracking(printerId); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error requesting start printer tracking.", re); + } + } + } + + public void stopPrinterStateTracking(PrinterId printerId) { + mHandler.obtainMessage(MyHandler.MSG_STOP_PRINTER_STATE_TRACKING, printerId).sendToTarget(); } - private void handleRequestPrinterUpdate(final PrinterId printerId) { + private void handleStopPrinterStateTracking(final PrinterId printerId) { throwIfDestroyed(); if (!isBound()) { ensureBound(); mPendingCommands.add(new Runnable() { @Override public void run() { - handleRequestPrinterUpdate(printerId); + handleStopPrinterStateTracking(printerId); } }); } else { if (DEBUG) { - Slog.i(LOG_TAG, "[user: " + mUserId + "] requestPrinterUpdate()"); + Slog.i(LOG_TAG, "[user: " + mUserId + "] handleStopPrinterTracking()"); } try { - mPrintService.requestPrinterUpdate(printerId); + mPrintService.stopPrinterStateTracking(printerId); } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error requesting a printer update.", re); + Slog.e(LOG_TAG, "Error requesting stop printer tracking.", re); } } } @@ -417,12 +504,14 @@ final class RemotePrintService implements DeathRecipient { public static final int MSG_DESTROY_PRINTER_DISCOVERY_SESSION = 2; public static final int MSG_START_PRINTER_DISCOVERY = 3; public static final int MSG_STOP_PRINTER_DISCOVERY = 4; - public static final int MSG_REQUEST_PRINTER_UPDATE = 5; - public static final int MSG_ON_ALL_PRINT_JOBS_HANDLED = 6; - public static final int MSG_ON_REQUEST_CANCEL_PRINT_JOB = 7; - public static final int MSG_ON_PRINT_JOB_QUEUED = 8; - public static final int MSG_DESTROY = 9; - public static final int MSG_BINDER_DIED = 10; + public static final int MSG_VALIDATE_PRINTERS = 5; + public static final int MSG_START_PRINTER_STATE_TRACKING = 6; + public static final int MSG_STOP_PRINTER_STATE_TRACKING = 7; + public static final int MSG_ON_ALL_PRINT_JOBS_HANDLED = 8; + public static final int MSG_ON_REQUEST_CANCEL_PRINT_JOB = 9; + public static final int MSG_ON_PRINT_JOB_QUEUED = 10; + public static final int MSG_DESTROY = 11; + public static final int MSG_BINDER_DIED = 12; public MyHandler(Looper looper) { super(looper, null, false); @@ -449,9 +538,19 @@ final class RemotePrintService implements DeathRecipient { handleStopPrinterDiscovery(); } break; - case MSG_REQUEST_PRINTER_UPDATE: { + case MSG_VALIDATE_PRINTERS: { + List<PrinterId> printerIds = (List<PrinterId>) message.obj; + handleValidatePrinters(printerIds); + } break; + + case MSG_START_PRINTER_STATE_TRACKING: { + PrinterId printerId = (PrinterId) message.obj; + handleStartPrinterStateTracking(printerId); + } break; + + case MSG_STOP_PRINTER_STATE_TRACKING: { PrinterId printerId = (PrinterId) message.obj; - handleRequestPrinterUpdate(printerId); + handleStopPrinterStateTracking(printerId); } break; case MSG_ON_ALL_PRINT_JOBS_HANDLED: { diff --git a/services/java/com/android/server/print/UserState.java b/services/java/com/android/server/print/UserState.java index c979a11..4a1b96b 100644 --- a/services/java/com/android/server/print/UserState.java +++ b/services/java/com/android/server/print/UserState.java @@ -19,8 +19,12 @@ package com.android.server.print; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; +import android.content.SharedPreferences.Editor; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; import android.os.Build; import android.os.Handler; import android.os.IBinder; @@ -46,6 +50,7 @@ import com.android.server.print.RemotePrintSpooler.PrintSpoolerCallbacks; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -63,6 +68,11 @@ final class UserState implements PrintSpoolerCallbacks { private static final char COMPONENT_NAME_SEPARATOR = ':'; + private static final String SHARED_PREFERENCES_FILE = "shared_prefs"; + + private static final String KEY_SYSTEM_PRINT_SERVICES_ENABLED = + "KEY_SYSTEM_PRINT_SERVICES_ENABLED"; + private final SimpleStringSplitter mStringColonSplitter = new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR); @@ -95,6 +105,7 @@ final class UserState implements PrintSpoolerCallbacks { mUserId = userId; mLock = lock; mSpooler = new RemotePrintSpooler(context, userId, this); + enableSystemPrintServicesOnce(); } @Override @@ -190,7 +201,7 @@ final class UserState implements PrintSpoolerCallbacks { } } - public void requestPrinterUpdate(PrinterId printerId) { + public void validatePrinters(List<PrinterId> printerIds) { synchronized (mLock) { throwIfDestroyedLocked(); // No services - nothing to do. @@ -202,7 +213,39 @@ final class UserState implements PrintSpoolerCallbacks { return; } // Request an updated. - mPrinterDiscoverySession.requestPrinterUpdateLocked(printerId); + mPrinterDiscoverySession.validatePrintersLocked(printerIds); + } + } + + public void startPrinterStateTracking(PrinterId printerId) { + synchronized (mLock) { + throwIfDestroyedLocked(); + // No services - nothing to do. + if (mActiveServices.isEmpty()) { + return; + } + // No session - nothing to do. + if (mPrinterDiscoverySession == null) { + return; + } + // Request start tracking the printer. + mPrinterDiscoverySession.startPrinterStateTrackingLocked(printerId); + } + } + + public void stopPrinterStateTracking(PrinterId printerId) { + synchronized (mLock) { + throwIfDestroyedLocked(); + // No services - nothing to do. + if (mActiveServices.isEmpty()) { + return; + } + // No session - nothing to do. + if (mPrinterDiscoverySession == null) { + return; + } + // Request stop tracking the printer. + mPrinterDiscoverySession.stopPrinterStateTrackingLocked(printerId); } } @@ -365,6 +408,36 @@ final class UserState implements PrintSpoolerCallbacks { return false; } + private void enableSystemPrintServicesOnce() { + SharedPreferences preferences = mContext.getSharedPreferences( + SHARED_PREFERENCES_FILE, Context.MODE_PRIVATE); + if (preferences.getInt(KEY_SYSTEM_PRINT_SERVICES_ENABLED, 0) == 0) { + Editor editor = preferences.edit(); + editor.putInt(KEY_SYSTEM_PRINT_SERVICES_ENABLED, 1); + editor.commit(); + + readInstalledPrintServicesLocked(); + + StringBuilder builder = new StringBuilder(); + + final int serviceCount = mInstalledServices.size(); + for (int i = 0; i < serviceCount; i++) { + ServiceInfo serviceInfo = mInstalledServices.get(i).getResolveInfo().serviceInfo; + if ((serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { + ComponentName serviceName = new ComponentName( + serviceInfo.packageName, serviceInfo.name); + if (builder.length() > 0) { + builder.append(":"); + } + builder.append(serviceName.flattenToString()); + } + } + + Settings.Secure.putStringForUser(mContext.getContentResolver(), + Settings.Secure.ENABLED_PRINT_SERVICES, builder.toString(), mUserId); + } + } + private void onConfigurationChangedLocked() { final int installedCount = mInstalledServices.size(); for (int i = 0; i < installedCount; i++) { @@ -415,6 +488,8 @@ final class UserState implements PrintSpoolerCallbacks { private final List<IBinder> mStartedPrinterDiscoveryTokens = new ArrayList<IBinder>(); + private final List<PrinterId> mStateTrackedPrinters = new ArrayList<PrinterId>(); + private final Handler mHandler; private boolean mIsDestroyed; @@ -461,14 +536,10 @@ final class UserState implements PrintSpoolerCallbacks { } // If printer discovery is ongoing and the start request has a list - // of printer to be checked, then we just request refreshing each of - // them rather making another start discovery request. + // of printer to be checked, then we just request validating them. if (!mStartedPrinterDiscoveryTokens.isEmpty() && priorityList != null && !priorityList.isEmpty()) { - final int priorityIdCount = priorityList.size(); - for (int i = 0; i < priorityIdCount; i++) { - requestPrinterUpdate(priorityList.get(i)); - } + validatePrinters(priorityList); return; } @@ -508,20 +579,97 @@ final class UserState implements PrintSpoolerCallbacks { .sendToTarget(); } - public void requestPrinterUpdateLocked(PrinterId printerId) { + public void validatePrintersLocked(List<PrinterId> printerIds) { if (mIsDestroyed) { - Log.w(LOG_TAG, "Not updating pritner - session destroyed"); + Log.w(LOG_TAG, "Not validating pritners - session destroyed"); return; } + + List<PrinterId> remainingList = new ArrayList<PrinterId>(printerIds); + while (!remainingList.isEmpty()) { + Iterator<PrinterId> iterator = remainingList.iterator(); + // Gather the printers per service and request a validation. + List<PrinterId> updateList = new ArrayList<PrinterId>(); + ComponentName serviceName = null; + while (iterator.hasNext()) { + PrinterId printerId = iterator.next(); + if (updateList.isEmpty()) { + updateList.add(printerId); + serviceName = printerId.getServiceName(); + iterator.remove(); + } else if (printerId.getServiceName().equals(serviceName)) { + updateList.add(printerId); + iterator.remove(); + } + } + // Schedule a notification of the service. + RemotePrintService service = mActiveServices.get(serviceName); + if (service != null) { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = service; + args.arg2 = updateList; + mHandler.obtainMessage(SessionHandler + .MSG_VALIDATE_PRINTERS, args) + .sendToTarget(); + } + } + } + + public final void startPrinterStateTrackingLocked(PrinterId printerId) { + if (mIsDestroyed) { + Log.w(LOG_TAG, "Not starting printer state tracking - session destroyed"); + return; + } + // If printer discovery is not started - nothing to do. + if (mStartedPrinterDiscoveryTokens.isEmpty()) { + return; + } + final boolean containedPrinterId = mStateTrackedPrinters.contains(printerId); + // Keep track of the number of requests to track this one. + mStateTrackedPrinters.add(printerId); + // If we were tracking this printer - nothing to do. + if (containedPrinterId) { + return; + } + // No service - nothing to do. RemotePrintService service = mActiveServices.get(printerId.getServiceName()); - if (service != null) { - SomeArgs args = SomeArgs.obtain(); - args.arg1 = service; - args.arg2 = printerId; - mHandler.obtainMessage(SessionHandler - .MSG_REQUEST_PRINTER_UPDATE, args) - .sendToTarget(); + if (service == null) { + return; } + // Ask the service to start tracking. + SomeArgs args = SomeArgs.obtain(); + args.arg1 = service; + args.arg2 = printerId; + mHandler.obtainMessage(SessionHandler + .MSG_START_PRINTER_STATE_TRACKING, args) + .sendToTarget(); + } + + public final void stopPrinterStateTrackingLocked(PrinterId printerId) { + if (mIsDestroyed) { + Log.w(LOG_TAG, "Not stopping printer state tracking - session destroyed"); + return; + } + // If printer discovery is not started - nothing to do. + if (mStartedPrinterDiscoveryTokens.isEmpty()) { + return; + } + // If we did not track this printer - nothing to do. + if (!mStateTrackedPrinters.remove(printerId)) { + return; + } + // No service - nothing to do. + RemotePrintService service = mActiveServices.get(printerId.getServiceName()); + if (service == null) { + return; + } + // Ask the service to start tracking. + SomeArgs args = SomeArgs.obtain(); + args.arg1 = service; + args.arg2 = printerId; + mHandler.obtainMessage(SessionHandler + .MSG_STOP_PRINTER_STATE_TRACKING, args) + .sendToTarget(); } public void onDestroyed() { @@ -533,6 +681,12 @@ final class UserState implements PrintSpoolerCallbacks { Log.w(LOG_TAG, "Not destroying - session destroyed"); return; } + // Make sure printer tracking is stopped. + final int printerCount = mStateTrackedPrinters.size(); + for (int i = 0; i < printerCount; i++) { + PrinterId printerId = mStateTrackedPrinters.get(i); + stopPrinterStateTracking(printerId); + } // Make sure discovery is stopped. final int observerCount = mStartedPrinterDiscoveryTokens.size(); for (int i = 0; i < observerCount; i++) { @@ -744,9 +898,19 @@ final class UserState implements PrintSpoolerCallbacks { } } - private void handleRequestPrinterUpdate(RemotePrintService service, + private void handleValidatePrinters(RemotePrintService service, + List<PrinterId> printerIds) { + service.validatePrinters(printerIds); + } + + private void handleStartPrinterStateTracking(RemotePrintService service, + PrinterId printerId) { + service.startPrinterStateTracking(printerId); + } + + private void handleStopPrinterStateTracking(RemotePrintService service, PrinterId printerId) { - service.requestPrinterUpdate(printerId); + service.stopPrinterStateTracking(printerId); } private void handlePrintersAdded(IPrinterDiscoveryObserver observer, @@ -804,7 +968,9 @@ final class UserState implements PrintSpoolerCallbacks { public static final int MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION = 9; public static final int MSG_DISPATCH_START_PRINTER_DISCOVERY = 10; public static final int MSG_DISPATCH_STOP_PRINTER_DISCOVERY = 11; - public static final int MSG_REQUEST_PRINTER_UPDATE = 12; + public static final int MSG_VALIDATE_PRINTERS = 12; + public static final int MSG_START_PRINTER_STATE_TRACKING = 13; + public static final int MSG_STOP_PRINTER_STATE_TRACKING = 14; SessionHandler(Looper looper) { super(looper, null, false); @@ -878,13 +1044,29 @@ final class UserState implements PrintSpoolerCallbacks { handleDispatchStopPrinterDiscovery(services); } break; - case MSG_REQUEST_PRINTER_UPDATE: { + case MSG_VALIDATE_PRINTERS: { + SomeArgs args = (SomeArgs) message.obj; + RemotePrintService service = (RemotePrintService) args.arg1; + List<PrinterId> printerIds = (List<PrinterId>) args.arg2; + args.recycle(); + handleValidatePrinters(service, printerIds); + } break; + + case MSG_START_PRINTER_STATE_TRACKING: { SomeArgs args = (SomeArgs) message.obj; RemotePrintService service = (RemotePrintService) args.arg1; PrinterId printerId = (PrinterId) args.arg2; args.recycle(); - handleRequestPrinterUpdate(service, printerId); + handleStartPrinterStateTracking(service, printerId); } break; + + case MSG_STOP_PRINTER_STATE_TRACKING: { + SomeArgs args = (SomeArgs) message.obj; + RemotePrintService service = (RemotePrintService) args.arg1; + PrinterId printerId = (PrinterId) args.arg2; + args.recycle(); + handleStopPrinterStateTracking(service, printerId); + } } } } |