Merge "Handle the case when KeyChain binding fails"
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 254456c..538319c 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -763,28 +763,33 @@
      * @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 @@
     }
 
     /**
+     * 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 @@
                     }
                 }
             }
+            @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 @@
                 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) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/CertificateMonitor.java b/services/devicepolicy/java/com/android/server/devicepolicy/CertificateMonitor.java
index 4a456f7..aa38880 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/CertificateMonitor.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/CertificateMonitor.java
@@ -17,7 +17,6 @@
 package com.android.server.devicepolicy;
 
 import android.app.Notification;
-import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -26,12 +25,9 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
-import android.graphics.Color;
-import android.os.Build;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.os.UserManager;
 import android.os.storage.StorageManager;
 import android.provider.Settings;
 import android.security.Credentials;
@@ -39,9 +35,9 @@
 import android.security.KeyChain.KeyChainConnection;
 import android.util.Log;
 
+import com.android.internal.R;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.internal.notification.SystemNotificationChannels;
-import com.android.internal.R;
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
@@ -49,7 +45,6 @@
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
 import java.util.List;
-import java.util.Set;
 
 public class CertificateMonitor {
     protected static final String LOG_TAG = DevicePolicyManagerService.LOG_TAG;
@@ -111,13 +106,13 @@
         }
     }
 
-    public List<String> getInstalledCaCertificates(UserHandle userHandle)
+    private List<String> getInstalledCaCertificates(UserHandle userHandle)
             throws RemoteException, RuntimeException {
         try (KeyChainConnection conn = mInjector.keyChainBindAsUser(userHandle)) {
             return conn.getService().getUserCaAliases().getList();
         } catch (InterruptedException e) {
             Thread.currentThread().interrupt();
-            return null;
+            throw new RuntimeException(e);
         } catch (AssertionError e) {
             throw new RuntimeException(e);
         }