diff options
Diffstat (limited to 'services/java/com/android/server/print/RemoteSpooler.java')
-rw-r--r-- | services/java/com/android/server/print/RemoteSpooler.java | 416 |
1 files changed, 416 insertions, 0 deletions
diff --git a/services/java/com/android/server/print/RemoteSpooler.java b/services/java/com/android/server/print/RemoteSpooler.java new file mode 100644 index 0000000..fef5818 --- /dev/null +++ b/services/java/com/android/server/print/RemoteSpooler.java @@ -0,0 +1,416 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.print; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Binder; +import android.os.IBinder; +import android.os.ParcelFileDescriptor; +import android.os.RemoteException; +import android.os.SystemClock; +import android.os.UserHandle; +import android.os.IBinder.DeathRecipient; +import android.print.IPrintAdapter; +import android.print.IPrintClient; +import android.print.IPrintSpoolerService; +import android.print.IPrintSpoolerServiceCallbacks; +import android.print.PrintAttributes; +import android.print.PrintJobInfo; +import android.util.Slog; +import android.util.TimedRemoteCaller; + +import java.io.IOException; +import java.util.List; +import java.util.concurrent.TimeoutException; + +/** + * This represents the remote print spooler as a local object to the + * PrintManagerSerivce. It is responsible to connecting to the remove + * spooler if needed, to make the timed out remote calls, and to handle + * remove exceptions. + */ +final class RemoteSpooler implements ServiceConnection, DeathRecipient { + + private static final String LOG_TAG = "Spooler"; + + private static final long BIND_SPOOLER_SERVICE_TIMEOUT = 10000; + + private final Object mLock = new Object(); + + private final Context mContext; + + private final Intent mIntent; + + private final GetPrintJobsCaller mGetPrintJobsCaller = new GetPrintJobsCaller(); + + private final CreatePrintJobCaller mCreatePrintJobCaller = new CreatePrintJobCaller(); + + private final CancelPrintJobCaller mCancelPrintJobCaller = new CancelPrintJobCaller(); + + private final GetPrintJobCaller mGetPrintJobCaller = new GetPrintJobCaller(); + + private final SetPrintJobStateCaller mSetPrintJobStatusCaller = new SetPrintJobStateCaller(); + + private final SetPrintJobTagCaller mSetPrintJobTagCaller = new SetPrintJobTagCaller(); + + private IPrintSpoolerService mRemoteInterface; + + private int mUserId = UserHandle.USER_NULL; + + public RemoteSpooler(Context context) { + mContext = context; + mIntent = new Intent(); + mIntent.setComponent(new ComponentName("com.android.printspooler", + "com.android.printspooler.PrintSpoolerService")); + } + + public List<PrintJobInfo> getPrintJobs(ComponentName componentName, int state, int appId, + int userId) { + try { + return mGetPrintJobsCaller.getPrintJobs(getRemoteInstance(userId), + componentName, state, appId); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error getting print jobs!", re); + } catch (TimeoutException te) { + Slog.e(LOG_TAG, "Error getting print jobs!", te); + } + return null; + } + + public PrintJobInfo createPrintJob(String printJobName, IPrintClient client, + IPrintAdapter printAdapter, PrintAttributes attributes, int appId, int userId) { + try { + return mCreatePrintJobCaller.createPrintJob(getRemoteInstance(userId), + printJobName, client, printAdapter, attributes, appId); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error creating print job!", re); + } catch (TimeoutException te) { + Slog.e(LOG_TAG, "Error creating print job!", te); + } + return null; + } + + public boolean cancelPrintJob(int printJobId, int appId, int userId) { + try { + return mCancelPrintJobCaller.cancelPrintJob(getRemoteInstance(userId), + printJobId, appId); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error canceling print job!", re); + } catch (TimeoutException te) { + Slog.e(LOG_TAG, "Error canceling print job!", te); + } + return false; + } + + public void writePrintJobData(ParcelFileDescriptor fd, int printJobId, int userId) { + try { + getRemoteInstance(userId).writePrintJobData(fd, printJobId); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error writing print job data!", re); + } catch (TimeoutException te) { + Slog.e(LOG_TAG, "Error writing print job data!", te); + } finally { + // We passed the file descriptor across and now the other + // side is responsible to close it, so close the local copy. + try { + fd.close(); + } catch (IOException ioe) { + /* ignore */ + } + } + } + + public PrintJobInfo getPrintJobInfo(int printJobId, int appId, int userId) { + try { + return mGetPrintJobCaller.getPrintJobInfo(getRemoteInstance(userId), + printJobId, appId); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error getting print job!", re); + } catch (TimeoutException te) { + Slog.e(LOG_TAG, "Error getting print job!", te); + } + return null; + } + + public boolean setPrintJobState(int printJobId, int state, int userId) { + try { + return mSetPrintJobStatusCaller.setPrintJobState(getRemoteInstance(userId), + printJobId, state); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error setting print job status!", re); + } catch (TimeoutException te) { + Slog.e(LOG_TAG, "Error setting print job status!", te); + } + return false; + } + + public boolean setPrintJobTag(int printJobId, String tag, int userId) { + try { + return mSetPrintJobTagCaller.setPrintJobTag(getRemoteInstance(userId), + printJobId, tag); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error setting print job tag!", re); + } catch (TimeoutException te) { + Slog.e(LOG_TAG, "Error setting print job tag!", te); + } + return false; + } + + @Override + public void onServiceDisconnected(ComponentName name) { + binderDied(); + } + + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + synchronized (mLock) { + try { + service.linkToDeath(this, 0); + mRemoteInterface = IPrintSpoolerService.Stub.asInterface(service); + } catch (RemoteException re) { + /* ignore */ + } + } + } + + private IPrintSpoolerService getRemoteInstance(int userId) throws TimeoutException { + synchronized (mLock) { + if (mRemoteInterface != null && mUserId == userId) { + return mRemoteInterface; + } + + final long identity = Binder.clearCallingIdentity(); + try { + if (mUserId != UserHandle.USER_NULL && mUserId != userId) { + unbind(); + } + + mContext.bindServiceAsUser(mIntent, this, + Context.BIND_AUTO_CREATE | Context.BIND_ALLOW_OOM_MANAGEMENT, + UserHandle.CURRENT); + } finally { + Binder.restoreCallingIdentity(identity); + } + + final long startMillis = SystemClock.uptimeMillis(); + while (true) { + if (mRemoteInterface != null) { + break; + } + final long elapsedMillis = SystemClock.uptimeMillis() - startMillis; + final long remainingMillis = BIND_SPOOLER_SERVICE_TIMEOUT - elapsedMillis; + if (remainingMillis <= 0) { + throw new TimeoutException("Cannot get spooler!"); + } + try { + mLock.wait(remainingMillis); + } catch (InterruptedException ie) { + /* ignore */ + } + } + + mUserId = userId; + + return mRemoteInterface; + } + } + + public void unbind() { + synchronized (mLock) { + if (mRemoteInterface != null) { + mContext.unbindService(this); + mRemoteInterface = null; + mUserId = UserHandle.USER_NULL; + } + } + } + + @Override + public void binderDied() { + synchronized (mLock) { + if (mRemoteInterface != null) { + mRemoteInterface.asBinder().unlinkToDeath(this, 0); + mRemoteInterface = null; + } + } + } + + private final class GetPrintJobsCaller extends TimedRemoteCaller<List<PrintJobInfo>> { + private final IPrintSpoolerServiceCallbacks mCallback; + + public GetPrintJobsCaller() { + super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS); + mCallback = new BasePrintSpoolerServiceCallbacks() { + @Override + public void onGetPrintJobsResult(List<PrintJobInfo> printJobs, int sequence) { + onRemoteMethodResult(printJobs, sequence); + } + }; + } + + public List<PrintJobInfo> getPrintJobs(IPrintSpoolerService target, + ComponentName componentName, int state, int appId) + throws RemoteException, TimeoutException { + final int sequence = onBeforeRemoteCall(); + target.getPrintJobs(mCallback, componentName, state, appId, sequence); + return getResultTimed(sequence); + } + } + + private final class CreatePrintJobCaller extends TimedRemoteCaller<PrintJobInfo> { + private final IPrintSpoolerServiceCallbacks mCallback; + + public CreatePrintJobCaller() { + super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS); + mCallback = new BasePrintSpoolerServiceCallbacks() { + @Override + public void onCreatePrintJobResult(PrintJobInfo printJob, int sequence) { + onRemoteMethodResult(printJob, sequence); + } + }; + } + + public PrintJobInfo createPrintJob(IPrintSpoolerService target, String printJobName, + IPrintClient client, IPrintAdapter printAdapter, PrintAttributes attributes, + int appId) throws RemoteException, TimeoutException { + final int sequence = onBeforeRemoteCall(); + target.createPrintJob(printJobName, client, printAdapter, attributes, + mCallback, appId, sequence); + return getResultTimed(sequence); + } + } + + private final class CancelPrintJobCaller extends TimedRemoteCaller<Boolean> { + private final IPrintSpoolerServiceCallbacks mCallback; + + public CancelPrintJobCaller() { + super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS); + mCallback = new BasePrintSpoolerServiceCallbacks() { + @Override + public void onCancelPrintJobResult(boolean canceled, int sequence) { + onRemoteMethodResult(canceled, sequence); + } + }; + } + + public boolean cancelPrintJob(IPrintSpoolerService target, int printJobId, + int appId) throws RemoteException, TimeoutException { + final int sequence = onBeforeRemoteCall(); + target.cancelPrintJob(printJobId, mCallback, appId, sequence); + return getResultTimed(sequence); + } + } + + private final class GetPrintJobCaller extends TimedRemoteCaller<PrintJobInfo> { + private final IPrintSpoolerServiceCallbacks mCallback; + + public GetPrintJobCaller() { + super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS); + mCallback = new BasePrintSpoolerServiceCallbacks() { + @Override + public void onGetPrintJobInfoResult(PrintJobInfo printJob, int sequence) { + onRemoteMethodResult(printJob, sequence); + } + }; + } + + public PrintJobInfo getPrintJobInfo(IPrintSpoolerService target, int printJobId, + int appId) throws RemoteException, TimeoutException { + final int sequence = onBeforeRemoteCall(); + target.getPrintJob(printJobId, mCallback, appId, sequence); + return getResultTimed(sequence); + } + } + + private final class SetPrintJobStateCaller extends TimedRemoteCaller<Boolean> { + private final IPrintSpoolerServiceCallbacks mCallback; + + public SetPrintJobStateCaller() { + super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS); + mCallback = new BasePrintSpoolerServiceCallbacks() { + @Override + public void onSetPrintJobStateResult(boolean success, int sequence) { + onRemoteMethodResult(success, sequence); + } + }; + } + + public boolean setPrintJobState(IPrintSpoolerService target, int printJobId, + int status) throws RemoteException, TimeoutException { + final int sequence = onBeforeRemoteCall(); + target.setPrintJobState(printJobId, status, mCallback, sequence); + return getResultTimed(sequence); + } + } + + private final class SetPrintJobTagCaller extends TimedRemoteCaller<Boolean> { + private final IPrintSpoolerServiceCallbacks mCallback; + + public SetPrintJobTagCaller() { + super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS); + mCallback = new BasePrintSpoolerServiceCallbacks() { + @Override + public void onSetPrintJobTagResult(boolean success, int sequence) { + onRemoteMethodResult(success, sequence); + } + }; + } + + public boolean setPrintJobTag(IPrintSpoolerService target, int printJobId, + String tag) throws RemoteException, TimeoutException { + final int sequence = onBeforeRemoteCall(); + target.setPrintJobTag(printJobId, tag, mCallback, sequence); + return getResultTimed(sequence); + } + } + + private abstract class BasePrintSpoolerServiceCallbacks + extends IPrintSpoolerServiceCallbacks.Stub { + @Override + public void onGetPrintJobsResult(List<PrintJobInfo> printJobIds, int sequence) { + /** do nothing */ + } + + @Override + public void onGetPrintJobInfoResult(PrintJobInfo printJob, int sequence) { + /** do nothing */ + } + + @Override + public void onCreatePrintJobResult(PrintJobInfo printJob, int sequence) { + /** do nothing */ + } + + @Override + public void onCancelPrintJobResult(boolean canceled, int sequence) { + /** do nothing */ + } + + @Override + public void onSetPrintJobStateResult(boolean success, int sequece) { + /** do nothing */ + } + + @Override + public void onSetPrintJobTagResult(boolean success, int sequence) { + /** do nothing */ + } + } +}
\ No newline at end of file |