From 7629a4b45e3d2ca4ea943724c6fa690b8355de82 Mon Sep 17 00:00:00 2001 From: Rubin Xu Date: Wed, 9 Oct 2019 11:24:57 +0100 Subject: Handle the case when KeyChain binding fails Binding to keychain can fail, for example when the target user is being removed. Handle this case gracefully and do not block the system server. Bug: 139554671 Test: none Change-Id: Ib68c873e367428b82f3cb2a81cafe1a59776336c --- keystore/java/android/security/KeyChain.java | 48 +++++++++++++++++++++------- 1 file changed, 37 insertions(+), 11 deletions(-) (limited to 'keystore/java/android/security/KeyChain.java') diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java index 254456cea536..538319c3f1d7 100644 --- a/keystore/java/android/security/KeyChain.java +++ b/keystore/java/android/security/KeyChain.java @@ -763,28 +763,33 @@ public final class KeyChain { * @see KeyChain#bind */ public static class KeyChainConnection implements Closeable { - private final Context context; - private final ServiceConnection serviceConnection; - private final IKeyChainService service; + private final Context mContext; + private final ServiceConnection mServiceConnection; + private final IKeyChainService mService; protected KeyChainConnection(Context context, ServiceConnection serviceConnection, IKeyChainService service) { - this.context = context; - this.serviceConnection = serviceConnection; - this.service = service; + this.mContext = context; + this.mServiceConnection = serviceConnection; + this.mService = service; } @Override public void close() { - context.unbindService(serviceConnection); + mContext.unbindService(mServiceConnection); } + + /** returns the service binder. */ public IKeyChainService getService() { - return service; + return mService; } } /** - * @hide for reuse by CertInstaller and Settings. - * + * Bind to KeyChainService in the current user. * Caller should call unbindService on the result when finished. + * + *@throws InterruptedException if interrupted during binding. + *@throws AssertionError if unable to bind to KeyChainService. + * @hide for reuse by CertInstaller and Settings. */ @WorkerThread public static KeyChainConnection bind(@NonNull Context context) throws InterruptedException { @@ -792,6 +797,11 @@ public final class KeyChain { } /** + * Bind to KeyChainService in the target user. + * Caller should call unbindService on the result when finished. + * + * @throws InterruptedException if interrupted during binding. + * @throws AssertionError if unable to bind to KeyChainService. * @hide */ @WorkerThread @@ -814,6 +824,16 @@ public final class KeyChain { } } } + @Override public void onBindingDied(ComponentName name) { + if (!mConnectedAtLeastOnce) { + mConnectedAtLeastOnce = true; + try { + q.put(null); + } catch (InterruptedException e) { + // will never happen, since the queue starts with one available slot + } + } + } @Override public void onServiceDisconnected(ComponentName name) {} }; Intent intent = new Intent(IKeyChainService.class.getName()); @@ -823,7 +843,13 @@ public final class KeyChain { intent, keyChainServiceConnection, Context.BIND_AUTO_CREATE, user)) { throw new AssertionError("could not bind to KeyChainService"); } - return new KeyChainConnection(context, keyChainServiceConnection, q.take()); + IKeyChainService service = q.take(); + if (service != null) { + return new KeyChainConnection(context, keyChainServiceConnection, service); + } else { + context.unbindService(keyChainServiceConnection); + throw new AssertionError("KeyChainService died while binding"); + } } private static void ensureNotOnMainThread(@NonNull Context context) { -- cgit v1.2.3