/**
   * Returns the {@code X509Certificate} chain for the requested alias, or null if no there is no
   * result.
   *
   * <p>This method may block while waiting for a connection to another process, and must never be
   * called from the main thread.
   *
   * @param alias The alias of the desired certificate chain, typically returned via {@link
   *     KeyChainAliasCallback#alias}.
   * @throws KeyChainException if the alias was valid but there was some problem accessing it.
   * @throws IllegalStateException if called from the main thread.
   */
  @Nullable
  @WorkerThread
  public static X509Certificate[] getCertificateChain(
      @NonNull Context context, @NonNull String alias)
      throws KeyChainException, InterruptedException {
    if (alias == null) {
      throw new NullPointerException("alias == null");
    }
    KeyChainConnection keyChainConnection = bind(context);
    try {
      IKeyChainService keyChainService = keyChainConnection.getService();

      final byte[] certificateBytes = keyChainService.getCertificate(alias);
      if (certificateBytes == null) {
        return null;
      }

      TrustedCertificateStore store = new TrustedCertificateStore();
      List<X509Certificate> chain = store.getCertificateChain(toCertificate(certificateBytes));
      return chain.toArray(new X509Certificate[chain.size()]);
    } catch (CertificateException e) {
      throw new KeyChainException(e);
    } catch (RemoteException e) {
      throw new KeyChainException(e);
    } catch (RuntimeException e) {
      // only certain RuntimeExceptions can be propagated across the IKeyChainService call
      throw new KeyChainException(e);
    } finally {
      keyChainConnection.close();
    }
  }
 /**
  * Returns the {@code PrivateKey} for the requested alias, or null if no there is no result.
  *
  * <p>This method may block while waiting for a connection to another process, and must never be
  * called from the main thread.
  *
  * @param alias The alias of the desired private key, typically returned via {@link
  *     KeyChainAliasCallback#alias}.
  * @throws KeyChainException if the alias was valid but there was some problem accessing it.
  * @throws IllegalStateException if called from the main thread.
  */
 @Nullable
 @WorkerThread
 public static PrivateKey getPrivateKey(@NonNull Context context, @NonNull String alias)
     throws KeyChainException, InterruptedException {
   if (alias == null) {
     throw new NullPointerException("alias == null");
   }
   KeyChainConnection keyChainConnection = bind(context);
   try {
     final IKeyChainService keyChainService = keyChainConnection.getService();
     final String keyId = keyChainService.requestPrivateKey(alias);
     if (keyId == null) {
       throw new KeyChainException("keystore had a problem");
     }
     return AndroidKeyStoreProvider.loadAndroidKeyStorePrivateKeyFromKeystore(
         KeyStore.getInstance(), keyId);
   } catch (RemoteException e) {
     throw new KeyChainException(e);
   } catch (RuntimeException e) {
     // only certain RuntimeExceptions can be propagated across the IKeyChainService call
     throw new KeyChainException(e);
   } catch (UnrecoverableKeyException e) {
     throw new KeyChainException(e);
   } finally {
     keyChainConnection.close();
   }
 }