diff options
Diffstat (limited to 'services')
6 files changed, 635 insertions, 178 deletions
diff --git a/services/java/Android.mk b/services/java/Android.mk index 95b28d9..8c3d0f0 100644 --- a/services/java/Android.mk +++ b/services/java/Android.mk @@ -11,7 +11,7 @@ LOCAL_SRC_FILES := \ LOCAL_MODULE:= services -LOCAL_JAVA_LIBRARIES := android.policy telephony-common +LOCAL_JAVA_LIBRARIES := android.policy conscrypt telephony-common include $(BUILD_JAVA_LIBRARY) diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java index 43f95c3..7e83396 100644 --- a/services/java/com/android/server/DevicePolicyManagerService.java +++ b/services/java/com/android/server/DevicePolicyManagerService.java @@ -16,11 +16,14 @@ package com.android.server; +import static android.Manifest.permission.MANAGE_CA_CERTIFICATES; + import com.android.internal.os.storage.ExternalStorageFormatter; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.JournaledFile; import com.android.internal.util.XmlUtils; import com.android.internal.widget.LockPatternUtils; +import com.android.org.conscrypt.TrustedCertificateStore; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -49,6 +52,7 @@ import android.content.pm.Signature; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.net.Uri; +import android.os.AsyncTask; import android.os.Binder; import android.os.Bundle; import android.os.Environment; @@ -66,7 +70,12 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; +import android.security.Credentials; +import android.security.IKeyChainService; +import android.security.KeyChain; +import android.security.KeyChain.KeyChainConnection; import android.util.AtomicFile; +import android.util.Log; import android.util.PrintWriterPrinter; import android.util.Printer; import android.util.Slog; @@ -75,6 +84,7 @@ import android.util.Xml; import android.view.IWindowManager; import android.view.WindowManagerPolicy; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; @@ -82,8 +92,14 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; +import java.security.KeyStore.TrustedCertificateEntry; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; import java.text.DateFormat; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -1870,6 +1886,76 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return !"".equals(state); } + public boolean installCaCert(byte[] certBuffer) throws RemoteException { + mContext.enforceCallingOrSelfPermission(MANAGE_CA_CERTIFICATES, null); + KeyChainConnection keyChainConnection = null; + byte[] pemCert; + try { + X509Certificate cert = parseCert(certBuffer); + pemCert = Credentials.convertToPem(cert); + } catch (CertificateException ce) { + Log.e(TAG, "Problem converting cert", ce); + return false; + } catch (IOException ioe) { + Log.e(TAG, "Problem reading cert", ioe); + return false; + } + try { + keyChainConnection = KeyChain.bind(mContext); + try { + keyChainConnection.getService().installCaCertificate(pemCert); + return true; + } finally { + if (keyChainConnection != null) { + keyChainConnection.close(); + keyChainConnection = null; + } + } + } catch (InterruptedException e1) { + Log.w(TAG, "installCaCertsToKeyChain(): ", e1); + Thread.currentThread().interrupt(); + } + return false; + } + + private static X509Certificate parseCert(byte[] certBuffer) + throws CertificateException, IOException { + CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); + return (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream( + certBuffer)); + } + + public void uninstallCaCert(final byte[] certBuffer) { + mContext.enforceCallingOrSelfPermission(MANAGE_CA_CERTIFICATES, null); + TrustedCertificateStore certStore = new TrustedCertificateStore(); + String alias = null; + try { + X509Certificate cert = parseCert(certBuffer); + alias = certStore.getCertificateAlias(cert); + } catch (CertificateException ce) { + Log.e(TAG, "Problem creating X509Certificate", ce); + return; + } catch (IOException ioe) { + Log.e(TAG, "Problem reading certificate", ioe); + return; + } + try { + KeyChainConnection keyChainConnection = KeyChain.bind(mContext); + IKeyChainService service = keyChainConnection.getService(); + try { + service.deleteCaCertificate(alias); + } catch (RemoteException e) { + Log.e(TAG, "from CaCertUninstaller: ", e); + } finally { + keyChainConnection.close(); + keyChainConnection = null; + } + } catch (InterruptedException ie) { + Log.w(TAG, "CaCertUninstaller: ", ie); + Thread.currentThread().interrupt(); + } + } + void wipeDataLocked(int flags) { // If the SD card is encrypted and non-removable, we have to force a wipe. boolean forceExtWipe = !Environment.isExternalStorageRemovable() && isExtStorageEncrypted(); diff --git a/services/java/com/android/server/connectivity/PacManager.java b/services/java/com/android/server/connectivity/PacManager.java index defe9f0..0b68ff5 100644 --- a/services/java/com/android/server/connectivity/PacManager.java +++ b/services/java/com/android/server/connectivity/PacManager.java @@ -1,14 +1,31 @@ +/** + * 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.connectivity; import android.app.AlarmManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; +import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.net.ConnectivityManager; +import android.content.ServiceConnection; import android.net.ProxyProperties; +import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; @@ -17,42 +34,26 @@ import android.provider.Settings; import android.text.TextUtils; import android.util.Log; +import com.android.internal.annotations.GuardedBy; import com.android.net.IProxyService; +import com.android.server.IoThread; +import libcore.io.Streams; -import org.apache.http.HttpEntity; -import org.apache.http.HttpException; -import org.apache.http.HttpHost; -import org.apache.http.HttpRequest; -import org.apache.http.HttpResponse; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.conn.params.ConnRouteParams; -import org.apache.http.conn.routing.HttpRoute; -import org.apache.http.conn.routing.HttpRoutePlanner; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.protocol.HttpContext; - -import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.InetAddress; -import java.net.ProxySelector; import java.net.URL; import java.net.URLConnection; /** * @hide */ -public class PacManager implements Runnable { - public static final int NO_ERROR = 0; - public static final int PERMISSION_DENIED = 1; - public static final String PROXY_SERVICE = "com.android.net.IProxyService"; +public class PacManager { + public static final String PROXY_PACKAGE = "com.android.pacprocessor"; + public static final String PROXY_SERVICE = "com.android.pacprocessor.PacService"; + public static final String PROXY_SERVICE_NAME = "com.android.net.IProxyService"; - private static final String TAG = "PACManager"; + private static final String TAG = "PacManager"; private static final String ACTION_PAC_REFRESH = "android.net.proxy.PAC_REFRESH"; @@ -64,31 +65,57 @@ public class PacManager implements Runnable { /** Keep these values up-to-date with ProxyService.java */ public static final String KEY_PROXY = "keyProxy"; private String mCurrentPac; - private volatile String mPacUrl; + @GuardedBy("mProxyLock") + private String mPacUrl; private AlarmManager mAlarmManager; + @GuardedBy("mProxyLock") private IProxyService mProxyService; private PendingIntent mPacRefreshIntent; + private ServiceConnection mConnection; private Context mContext; private int mCurrentDelay; + /** + * Used for locking when setting mProxyService and all references to mPacUrl or mCurrentPac. + */ + private final Object mProxyLock = new Object(); + + private Runnable mPacDownloader = new Runnable() { + @Override + public void run() { + String file; + synchronized (mProxyLock) { + if (mPacUrl == null) return; + try { + file = get(mPacUrl); + } catch (IOException ioe) { + file = null; + Log.w(TAG, "Failed to load PAC file: " + ioe); + } + } + if (file != null) { + synchronized (mProxyLock) { + if (!file.equals(mCurrentPac)) { + setCurrentProxyScript(file); + } + } + longSchedule(); + } else { + reschedule(); + } + } + }; + class PacRefreshIntentReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { - new Thread(PacManager.this).start(); + IoThread.getHandler().post(mPacDownloader); } } public PacManager(Context context) { mContext = context; - mProxyService = IProxyService.Stub.asInterface( - ServiceManager.getService(PROXY_SERVICE)); - if (mProxyService == null) { - // Added because of b10267814 where mako is restarting. - Log.e(TAG, "PacManager: no proxy service"); - } else { - Log.d(TAG, "PacManager: mProxyService available"); - } mPacRefreshIntent = PendingIntent.getBroadcast( context, 0, new Intent(ACTION_PAC_REFRESH), 0); @@ -103,26 +130,28 @@ public class PacManager implements Runnable { return mAlarmManager; } - public void setCurrentProxyScriptUrl(ProxyProperties proxy) { - if (mProxyService == null) { - Log.e(TAG, "setCurrentProxyScriptUrl: no proxy service"); - return; - } + public synchronized void setCurrentProxyScriptUrl(ProxyProperties proxy) { if (!TextUtils.isEmpty(proxy.getPacFileUrl())) { - try { - mProxyService.startPacSystem(); + synchronized (mProxyLock) { mPacUrl = proxy.getPacFileUrl(); - mCurrentDelay = DELAY_1; - getAlarmManager().cancel(mPacRefreshIntent); - new Thread(this).start(); - } catch (RemoteException e) { - Log.e(TAG, "Unable to reach ProxyService - PAC will not be started", e); } + mCurrentDelay = DELAY_1; + getAlarmManager().cancel(mPacRefreshIntent); + bind(); } else { - try { - mProxyService.stopPacSystem(); - } catch (RemoteException e) { - e.printStackTrace(); + getAlarmManager().cancel(mPacRefreshIntent); + synchronized (mProxyLock) { + mPacUrl = null; + mCurrentPac = null; + if (mProxyService != null) { + try { + mProxyService.stopPacSystem(); + } catch (RemoteException e) { + Log.w(TAG, "Failed to stop PAC service", e); + } finally { + unbind(); + } + } } } } @@ -132,51 +161,10 @@ public class PacManager implements Runnable { * * @throws IOException */ - public static String get(String urlString) throws IOException { + private static String get(String urlString) throws IOException { URL url = new URL(urlString); URLConnection urlConnection = url.openConnection(java.net.Proxy.NO_PROXY); - BufferedReader in = new BufferedReader(new InputStreamReader( - urlConnection.getInputStream())); - String inputLine; - String resp = ""; - while ((inputLine = in.readLine()) != null) { - resp = resp + inputLine + "\n"; - } - in.close(); - return resp; - } - - private static String toString(InputStream content) throws IOException { - StringBuffer buffer = new StringBuffer(); - String line; - BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(content)); - - while ((line = bufferedReader.readLine()) != null) { - if (buffer.length() != 0) { - buffer.append('\n'); - } - buffer.append(line); - } - - return buffer.toString(); - } - - @Override - public void run() { - String file; - try { - file = get(mPacUrl); - } catch (IOException ioe) { - file = null; - } - if (file != null) { - if (!file.equals(mCurrentPac)) { - setCurrentProxyScript(file); - } - longSchedule(); - } else { - reschedule(); - } + return new String(Streams.readFully(urlConnection.getInputStream())); } private int getNextDelay(int currentDelay) { @@ -227,14 +215,60 @@ public class PacManager implements Runnable { return false; } try { - if (mProxyService.setPacFile(script) != NO_ERROR) { - Log.e(TAG, "Unable to parse proxy script."); - return false; - } + mProxyService.setPacFile(script); mCurrentPac = script; } catch (RemoteException e) { Log.e(TAG, "Unable to set PAC file", e); } return true; } + + private void bind() { + if (mContext == null) { + Log.e(TAG, "No context for binding"); + return; + } + Intent intent = new Intent(); + intent.setClassName(PROXY_PACKAGE, PROXY_SERVICE); + mConnection = new ServiceConnection() { + @Override + public void onServiceDisconnected(ComponentName component) { + synchronized (mProxyLock) { + mProxyService = null; + } + } + + @Override + public void onServiceConnected(ComponentName component, IBinder binder) { + synchronized (mProxyLock) { + try { + Log.d(TAG, "Adding service " + PROXY_SERVICE_NAME + " " + + binder.getInterfaceDescriptor()); + } catch (RemoteException e1) { + Log.e(TAG, "Remote Exception", e1); + } + ServiceManager.addService(PROXY_SERVICE_NAME, binder); + mProxyService = IProxyService.Stub.asInterface(binder); + if (mProxyService == null) { + Log.e(TAG, "No proxy service"); + } else { + try { + mProxyService.startPacSystem(); + } catch (RemoteException e) { + Log.e(TAG, "Unable to reach ProxyService - PAC will not be started", e); + } + IoThread.getHandler().post(mPacDownloader); + } + } + } + }; + Log.e(TAG, "Attempting to bind"); + mContext.bindService(intent, mConnection, + Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND | Context.BIND_NOT_VISIBLE); + } + + private void unbind() { + mContext.unbindService(mConnection); + mConnection = null; + } } diff --git a/services/java/com/android/server/print/RemotePrintService.java b/services/java/com/android/server/print/RemotePrintService.java index 491dddc..5c68460 100644 --- a/services/java/com/android/server/print/RemotePrintService.java +++ b/services/java/com/android/server/print/RemotePrintService.java @@ -30,8 +30,6 @@ import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.UserHandle; -import android.print.IPrinterDiscoverySessionController; -import android.print.IPrinterDiscoverySessionObserver; import android.print.PrintJobInfo; import android.print.PrintManager; import android.print.PrinterId; @@ -79,6 +77,10 @@ final class RemotePrintService implements DeathRecipient { private boolean mDestroyed; + private boolean mAllPrintJobsHandled; + + private boolean mHasPrinterDiscoverySession; + public RemotePrintService(Context context, ComponentName componentName, int userId, RemotePrintSpooler spooler) { mContext = context; @@ -97,6 +99,8 @@ final class RemotePrintService implements DeathRecipient { private void handleDestroy() { throwIfDestroyed(); ensureUnbound(); + mAllPrintJobsHandled = false; + mHasPrinterDiscoverySession = false; mDestroyed = true; } @@ -110,18 +114,27 @@ final class RemotePrintService implements DeathRecipient { } private void handleBinderDied() { + mAllPrintJobsHandled = false; + mHasPrinterDiscoverySession = false; mPendingCommands.clear(); ensureUnbound(); } private void handleOnAllPrintJobsHandled() { throwIfDestroyed(); + + mAllPrintJobsHandled = true; + if (isBound()) { if (DEBUG) { Slog.i(LOG_TAG, "[user: " + mUserId + "] handleOnAllPrintJobsHandled()"); } - // If bound and all the work is completed, then unbind. - ensureUnbound(); + + // If the service has a printer discovery session + // created we should not disconnect from it just yet. + if (!mHasPrinterDiscoverySession) { + ensureUnbound(); + } } } @@ -153,6 +166,9 @@ final class RemotePrintService implements DeathRecipient { private void handleOnPrintJobQueued(final PrintJobInfo printJob) { throwIfDestroyed(); + + mAllPrintJobsHandled = false; + if (!isBound()) { ensureBound(); mPendingCommands.add(new Runnable() { @@ -173,20 +189,18 @@ final class RemotePrintService implements DeathRecipient { } } - public void createPrinterDiscoverySession(IPrinterDiscoverySessionObserver observer) { - mHandler.obtainMessage(MyHandler.MSG_CREATE_PRINTER_DISCOVERY_SESSION, - observer).sendToTarget(); + public void createPrinterDiscoverySession() { + mHandler.sendEmptyMessage(MyHandler.MSG_CREATE_PRINTER_DISCOVERY_SESSION); } - private void handleCreatePrinterDiscoverySession( - final IPrinterDiscoverySessionObserver observer) { + private void handleCreatePrinterDiscoverySession() { throwIfDestroyed(); if (!isBound()) { ensureBound(); mPendingCommands.add(new Runnable() { @Override public void run() { - handleCreatePrinterDiscoverySession(observer); + handleCreatePrinterDiscoverySession(); } }); } else { @@ -194,9 +208,126 @@ final class RemotePrintService implements DeathRecipient { Slog.i(LOG_TAG, "[user: " + mUserId + "] createPrinterDiscoverySession()"); } try { - mPrintService.createPrinterDiscoverySession(observer); + mPrintService.createPrinterDiscoverySession(); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error creating printer dicovery session.", re); + } + + mHasPrinterDiscoverySession = true; + } + } + + public void destroyPrinterDiscoverySession() { + mHandler.sendEmptyMessage(MyHandler.MSG_DESTROY_PRINTER_DISCOVERY_SESSION); + } + + private void handleDestroyPrinterDiscoverySession() { + throwIfDestroyed(); + if (!isBound()) { + ensureBound(); + mPendingCommands.add(new Runnable() { + @Override + public void run() { + handleDestroyPrinterDiscoverySession(); + } + }); + } else { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserId + "] destroyPrinterDiscoverySession()"); + } + + mHasPrinterDiscoverySession = false; + + try { + mPrintService.destroyPrinterDiscoverySession(); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error destroying printer dicovery session.", re); + } + + // If the service has no print jobs and no active discovery + // session anymore we should disconnect from it. + if (mAllPrintJobsHandled) { + ensureUnbound(); + } + } + } + + public void startPrinterDiscovery(List<PrinterId> priorityList) { + mHandler.obtainMessage(MyHandler.MSG_START_PRINTER_DISCOVERY, + priorityList).sendToTarget(); + } + + private void handleStartPrinterDiscovery(final List<PrinterId> priorityList) { + throwIfDestroyed(); + if (!isBound()) { + ensureBound(); + mPendingCommands.add(new Runnable() { + @Override + public void run() { + handleStartPrinterDiscovery(priorityList); + } + }); + } else { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserId + "] startPrinterDiscovery()"); + } + try { + mPrintService.startPrinterDiscovery(priorityList); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error starting printer dicovery.", re); + } + } + } + + public void stopPrinterDiscovery() { + mHandler.sendEmptyMessage(MyHandler.MSG_STOP_PRINTER_DISCOVERY); + } + + private void handleStopPrinterDiscovery() { + throwIfDestroyed(); + if (!isBound()) { + ensureBound(); + mPendingCommands.add(new Runnable() { + @Override + public void run() { + handleStopPrinterDiscovery(); + } + }); + } else { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserId + "] stopPrinterDiscovery()"); + } + try { + mPrintService.stopPrinterDiscovery(); } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error announcing start printer dicovery.", re); + Slog.e(LOG_TAG, "Error stopping printer dicovery.", re); + } + } + } + + public void requestPrinterUpdate(PrinterId printerId) { + mHandler.obtainMessage(MyHandler.MSG_REQUEST_PRINTER_UPDATE, + printerId).sendToTarget(); + } + + private void handleRequestPrinterUpdate(final PrinterId printerId) { + throwIfDestroyed(); + if (!isBound()) { + ensureBound(); + mPendingCommands.add(new Runnable() { + @Override + public void run() { + handleRequestPrinterUpdate(printerId); + } + }); + } else { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserId + "] requestPrinterUpdate()"); + } + try { + mPrintService.requestPrinterUpdate(printerId); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error requesting a printer update.", re); } } } @@ -279,20 +410,47 @@ final class RemotePrintService implements DeathRecipient { } private final class MyHandler extends Handler { - public static final int MSG_ON_ALL_PRINT_JOBS_HANDLED = 1; - public static final int MSG_ON_REQUEST_CANCEL_PRINT_JOB = 2; - public static final int MSG_ON_PRINT_JOB_QUEUED = 3; - public static final int MSG_CREATE_PRINTER_DISCOVERY_SESSION = 4; - public static final int MSG_DESTROY = 6; - public static final int MSG_BINDER_DIED = 7; + public static final int MSG_CREATE_PRINTER_DISCOVERY_SESSION = 1; + 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 MyHandler(Looper looper) { super(looper, null, false); } @Override + @SuppressWarnings("unchecked") public void handleMessage(Message message) { switch (message.what) { + case MSG_CREATE_PRINTER_DISCOVERY_SESSION: { + handleCreatePrinterDiscoverySession(); + } break; + + case MSG_DESTROY_PRINTER_DISCOVERY_SESSION: { + handleDestroyPrinterDiscoverySession(); + } break; + + case MSG_START_PRINTER_DISCOVERY: { + List<PrinterId> priorityList = (ArrayList<PrinterId>) message.obj; + handleStartPrinterDiscovery(priorityList); + } break; + + case MSG_STOP_PRINTER_DISCOVERY: { + handleStopPrinterDiscovery(); + } break; + + case MSG_REQUEST_PRINTER_UPDATE: { + PrinterId printerId = (PrinterId) message.obj; + handleRequestPrinterUpdate(printerId); + } break; + case MSG_ON_ALL_PRINT_JOBS_HANDLED: { handleOnAllPrintJobsHandled(); } break; @@ -307,13 +465,6 @@ final class RemotePrintService implements DeathRecipient { handleOnPrintJobQueued(printJob); } break; - case MSG_CREATE_PRINTER_DISCOVERY_SESSION: { - IPrinterDiscoverySessionObserver observer = - (IPrinterDiscoverySessionObserver) message.obj; - handleCreatePrinterDiscoverySession(new SecurePrinterDiscoverySessionObserver( - mComponentName, observer)); - } break; - case MSG_DESTROY: { handleDestroy(); } break; @@ -363,7 +514,7 @@ final class RemotePrintService implements DeathRecipient { } @Override - public boolean setPrintJobState(int printJobId, int state, CharSequence error) { + public boolean setPrintJobState(int printJobId, int state, String error) { RemotePrintService service = mWeakService.get(); if (service != null) { final long identity = Binder.clearCallingIdentity(); @@ -402,79 +553,70 @@ final class RemotePrintService implements DeathRecipient { } } } - } - - private static final class SecurePrinterDiscoverySessionObserver - extends IPrinterDiscoverySessionObserver.Stub { - private final ComponentName mComponentName; - - private final IPrinterDiscoverySessionObserver mDecoratedObsever; - - public SecurePrinterDiscoverySessionObserver(ComponentName componentName, - IPrinterDiscoverySessionObserver observer) { - mComponentName = componentName; - mDecoratedObsever = observer; - } @Override public void onPrintersAdded(List<PrinterInfo> printers) { - throwIfPrinterIdsForPrinterInfoTampered(printers); - try { - mDecoratedObsever.onPrintersAdded(printers); - } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error delegating to onPrintersAdded", re); - } - } - - @Override - public void onPrintersUpdated(List<PrinterInfo> printers) { - throwIfPrinterIdsForPrinterInfoTampered(printers); - try { - mDecoratedObsever.onPrintersUpdated(printers); - } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error delegating to onPrintersUpdated.", re); + RemotePrintService service = mWeakService.get(); + if (service != null) { + throwIfPrinterIdsForPrinterInfoTampered(service.mComponentName, printers); + final long identity = Binder.clearCallingIdentity(); + try { + service.mSpooler.onPrintersAdded(printers); + } finally { + Binder.restoreCallingIdentity(identity); + } } } @Override public void onPrintersRemoved(List<PrinterId> printerIds) { - throwIfPrinterIdsTampered(printerIds); - try { - mDecoratedObsever.onPrintersRemoved(printerIds); - } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error delegating to onPrintersRemoved", re); + RemotePrintService service = mWeakService.get(); + if (service != null) { + throwIfPrinterIdsTampered(service.mComponentName, printerIds); + final long identity = Binder.clearCallingIdentity(); + try { + service.mSpooler.onPrintersRemoved(printerIds); + } finally { + Binder.restoreCallingIdentity(identity); + } } } @Override - public void setController(IPrinterDiscoverySessionController controller) { - try { - mDecoratedObsever.setController(controller); - } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error setting controller", re); + public void onPrintersUpdated(List<PrinterInfo> printers) { + RemotePrintService service = mWeakService.get(); + if (service != null) { + throwIfPrinterIdsForPrinterInfoTampered(service.mComponentName, printers); + final long identity = Binder.clearCallingIdentity(); + try { + service.mSpooler.onPrintersUpdated(printers); + } finally { + Binder.restoreCallingIdentity(identity); + } } } - private void throwIfPrinterIdsForPrinterInfoTampered( + private void throwIfPrinterIdsForPrinterInfoTampered(ComponentName serviceName, List<PrinterInfo> printerInfos) { final int printerInfoCount = printerInfos.size(); for (int i = 0; i < printerInfoCount; i++) { PrinterId printerId = printerInfos.get(i).getId(); - throwIfPrinterIdTampered(printerId); + throwIfPrinterIdTampered(serviceName, printerId); } } - private void throwIfPrinterIdsTampered(List<PrinterId> printerIds) { + private void throwIfPrinterIdsTampered(ComponentName serviceName, + List<PrinterId> printerIds) { final int printerIdCount = printerIds.size(); for (int i = 0; i < printerIdCount; i++) { PrinterId printerId = printerIds.get(i); - throwIfPrinterIdTampered(printerId); + throwIfPrinterIdTampered(serviceName, printerId); } } - private void throwIfPrinterIdTampered(PrinterId printerId) { + private void throwIfPrinterIdTampered(ComponentName serviceName, PrinterId printerId) { if (printerId == null || printerId.getServiceName() == null - || !printerId.getServiceName().equals(mComponentName)) { + || !printerId.getServiceName().equals(serviceName)) { throw new IllegalArgumentException("Invalid printer id: " + printerId); } } diff --git a/services/java/com/android/server/print/RemotePrintSpooler.java b/services/java/com/android/server/print/RemotePrintSpooler.java index c932e9b..d261288 100644 --- a/services/java/com/android/server/print/RemotePrintSpooler.java +++ b/services/java/com/android/server/print/RemotePrintSpooler.java @@ -32,9 +32,10 @@ import android.print.IPrintDocumentAdapter; import android.print.IPrintSpooler; import android.print.IPrintSpoolerCallbacks; import android.print.IPrintSpoolerClient; -import android.print.IPrinterDiscoverySessionObserver; import android.print.PrintAttributes; import android.print.PrintJobInfo; +import android.print.PrinterId; +import android.print.PrinterInfo; import android.util.Slog; import android.util.TimedRemoteCaller; @@ -92,7 +93,11 @@ final class RemotePrintSpooler { public static interface PrintSpoolerCallbacks { public void onPrintJobQueued(PrintJobInfo printJob); public void onAllPrintJobsForServiceHandled(ComponentName printService); - public void createPrinterDiscoverySession(IPrinterDiscoverySessionObserver observer); + public void createPrinterDiscoverySession(); + public void destroyPrinterDiscoverySession(); + public void startPrinterDiscovery(List<PrinterId> priorityList); + public void stopPrinterDiscovery(); + public void requestPrinterUpdate(PrinterId printerId); } public RemotePrintSpooler(Context context, int userId, @@ -209,7 +214,7 @@ final class RemotePrintSpooler { return null; } - public final boolean setPrintJobState(int printJobId, int state, CharSequence error) { + public final boolean setPrintJobState(int printJobId, int state, String error) { throwIfCalledOnMainThread(); synchronized (mLock) { throwIfDestroyedLocked(); @@ -300,6 +305,78 @@ final class RemotePrintSpooler { } } + public final void onPrintersAdded(List<PrinterInfo> printers) { + throwIfCalledOnMainThread(); + synchronized (mLock) { + throwIfDestroyedLocked(); + mCanUnbind = false; + } + try { + getRemoteInstanceLazy().onPrintersAdded(printers); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error adding printers.", re); + } catch (TimeoutException te) { + Slog.e(LOG_TAG, "Error adding printers.", te); + } finally { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + + "] onPrintersAdded()"); + } + synchronized (mLock) { + mCanUnbind = true; + mLock.notifyAll(); + } + } + } + + public final void onPrintersRemoved(List<PrinterId> printerIds) { + throwIfCalledOnMainThread(); + synchronized (mLock) { + throwIfDestroyedLocked(); + mCanUnbind = false; + } + try { + getRemoteInstanceLazy().onPrintersRemoved(printerIds); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error removing printers.", re); + } catch (TimeoutException te) { + Slog.e(LOG_TAG, "Error removing printers.", te); + } finally { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + + "] onPrintersRemoved()"); + } + synchronized (mLock) { + mCanUnbind = true; + mLock.notifyAll(); + } + } + } + + public final void onPrintersUpdated(List<PrinterInfo> printers) { + throwIfCalledOnMainThread(); + synchronized (mLock) { + throwIfDestroyedLocked(); + mCanUnbind = false; + } + try { + getRemoteInstanceLazy().onPrintersUpdated(printers); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error updating printers.", re); + } catch (TimeoutException te) { + Slog.e(LOG_TAG, "Error updating printers.", te); + } finally { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() + + "] onPrintersUpdted()"); + } + synchronized (mLock) { + mCanUnbind = true; + mLock.notifyAll(); + } + } + } + private IPrintSpooler getRemoteInstanceLazy() throws TimeoutException { synchronized (mLock) { if (mRemoteInstance != null) { @@ -488,7 +565,7 @@ final class RemotePrintSpooler { } public boolean setPrintJobState(IPrintSpooler target, int printJobId, - int status, CharSequence error) throws RemoteException, TimeoutException { + int status, String error) throws RemoteException, TimeoutException { final int sequence = onBeforeRemoteCall(); target.setPrintJobState(printJobId, status, error, mCallback, sequence); return getResultTimed(sequence); @@ -597,12 +674,64 @@ final class RemotePrintSpooler { } @Override - public void createPrinterDiscoverySession(IPrinterDiscoverySessionObserver observer) { + public void createPrinterDiscoverySession() { + RemotePrintSpooler spooler = mWeakSpooler.get(); + if (spooler != null) { + final long identity = Binder.clearCallingIdentity(); + try { + spooler.mCallbacks.createPrinterDiscoverySession(); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + } + + @Override + public void destroyPrinterDiscoverySession() { + RemotePrintSpooler spooler = mWeakSpooler.get(); + if (spooler != null) { + final long identity = Binder.clearCallingIdentity(); + try { + spooler.mCallbacks.destroyPrinterDiscoverySession(); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + } + + @Override + public void startPrinterDiscovery(List<PrinterId> priorityList) { + RemotePrintSpooler spooler = mWeakSpooler.get(); + if (spooler != null) { + final long identity = Binder.clearCallingIdentity(); + try { + spooler.mCallbacks.startPrinterDiscovery(priorityList); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + } + + @Override + public void stopPrinterDiscovery() { + RemotePrintSpooler spooler = mWeakSpooler.get(); + if (spooler != null) { + final long identity = Binder.clearCallingIdentity(); + try { + spooler.mCallbacks.stopPrinterDiscovery(); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + } + + @Override + public void requestPrinterUpdate(PrinterId printerId) { RemotePrintSpooler spooler = mWeakSpooler.get(); if (spooler != null) { final long identity = Binder.clearCallingIdentity(); try { - spooler.mCallbacks.createPrinterDiscoverySession(observer); + spooler.mCallbacks.requestPrinterUpdate(printerId); } finally { Binder.restoreCallingIdentity(identity); } diff --git a/services/java/com/android/server/print/UserState.java b/services/java/com/android/server/print/UserState.java index ffcc9c3..9d7cfdd 100644 --- a/services/java/com/android/server/print/UserState.java +++ b/services/java/com/android/server/print/UserState.java @@ -21,8 +21,8 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.print.IPrinterDiscoverySessionObserver; import android.print.PrintJobInfo; +import android.print.PrinterId; import android.printservice.PrintServiceInfo; import android.provider.Settings; import android.text.TextUtils; @@ -105,7 +105,7 @@ final class UserState implements PrintSpoolerCallbacks { } @Override - public void createPrinterDiscoverySession(IPrinterDiscoverySessionObserver observer) { + public void createPrinterDiscoverySession() { final List<RemotePrintService> services; synchronized (mLock) { throwIfDestroyedLocked(); @@ -117,7 +117,73 @@ final class UserState implements PrintSpoolerCallbacks { final int serviceCount = services.size(); for (int i = 0; i < serviceCount; i++) { RemotePrintService service = services.get(i); - service.createPrinterDiscoverySession(observer); + service.createPrinterDiscoverySession(); + } + } + + @Override + public void destroyPrinterDiscoverySession() { + final List<RemotePrintService> services; + synchronized (mLock) { + throwIfDestroyedLocked(); + if (mActiveServices.isEmpty()) { + return; + } + services = new ArrayList<RemotePrintService>(mActiveServices.values()); + } + final int serviceCount = services.size(); + for (int i = 0; i < serviceCount; i++) { + RemotePrintService service = services.get(i); + service.destroyPrinterDiscoverySession(); + } + } + + @Override + public void startPrinterDiscovery(List<PrinterId> printerIds) { + final List<RemotePrintService> services; + synchronized (mLock) { + throwIfDestroyedLocked(); + if (mActiveServices.isEmpty()) { + return; + } + services = new ArrayList<RemotePrintService>(mActiveServices.values()); + } + final int serviceCount = services.size(); + for (int i = 0; i < serviceCount; i++) { + RemotePrintService service = services.get(i); + service.startPrinterDiscovery(printerIds); + } + } + + @Override + public void stopPrinterDiscovery() { + final List<RemotePrintService> services; + synchronized (mLock) { + throwIfDestroyedLocked(); + if (mActiveServices.isEmpty()) { + return; + } + services = new ArrayList<RemotePrintService>(mActiveServices.values()); + } + final int serviceCount = services.size(); + for (int i = 0; i < serviceCount; i++) { + RemotePrintService service = services.get(i); + service.stopPrinterDiscovery(); + } + } + + @Override + public void requestPrinterUpdate(PrinterId printerId) { + final RemotePrintService service; + synchronized (mLock) { + throwIfDestroyedLocked(); + if (mActiveServices.isEmpty()) { + return; + } + service = mActiveServices.get(printerId.getServiceName()); + } + if (service != null) { + service.requestPrinterUpdate(printerId); } } |